標籤: 潭子電動車

  • 這三款國產小型SUV都帶全景攝像頭,最低只要7萬多

    這三款國產小型SUV都帶全景攝像頭,最低只要7萬多

    動力總成上,S3有1。5L與1。6L兩款發動機可選,前者最大輸出113馬力和146牛米,後者最大輸出120馬力和150牛米,與它們匹配的有6擋手動和CVT變速箱。內飾上以簡潔為主,輔以一些銀色和碳纖維裝飾條來襯托,更多的橫向設計,看起來很舒展。

    新手上路,最怕的是什麼?當然是怕去到一些人多路窄的地方來個倒車入庫或者側方停車,既要瞻前,又要顧后,還要控制油門剎車,簡直就是影分身都忙不過來。

    不過,隨着汽車工業的發展,有一項高級實用配置開始漸漸下放到一些10萬元以下的車,那就是全景攝像頭。只要有了這個東西,倒車就從容許多了。因此,編者我就給大家推薦三款10萬內帶全景攝像頭的國產小型SUV。

    凱翼汽車-凱翼X3

    指導價:6.66-9.69萬

    帶全景攝像頭的車型:7.99萬的手動智聯IV版、8.69萬的手動智聯V版、8.99萬的CVT智聯IV版和CVT智聯V版

    編者點評:整個圖像的分辨率還可以,四個角落的拼接自然,這樣的價位確實很難再挑剔什麼。除此以外,這四個攝像頭還能充當行車記錄儀,讓各種碰瓷黨無處可逃。最方便的是,可以在屏幕上選擇錄像重放,讓碰瓷黨當即現形。這個功能,即便在不少豪車上也是沒有的,能出現在一輛國產小型SUV上,確實逆天了!

    動力方面,凱翼X3用的是1.6L發動機,與之匹配的是5擋手動和CVT變速箱,最大輸出126馬力和160牛米。內飾以黑色為主,各種設計都是一板一眼,雖沒新奇的地方,但勝在簡約耐看。

    江淮汽車-瑞風S3

    指導價:6.58-9.58萬

    帶全景攝像頭的車型:8.58萬的手動智能互聯型和9.58萬的CVT智能互聯型

    編者點評:S3的圖像显示比凱翼X3要稍差,而且銜接處的畸變有點大,不夠自然。但這兩款車型都帶前後駐車雷達,所以結合著來使用,各種停車還是游刃有餘的。

    動力總成上,S3有1.5L與1.6L兩款發動機可選,前者最大輸出113馬力和146牛米,後者最大輸出120馬力和150牛米,與它們匹配的有6擋手動和CVT變速箱。內飾上以簡潔為主,輔以一些銀色和碳纖維裝飾條來襯托,更多的橫向設計,看起來很舒展。

    比亞迪-元

    指導價:5.99-24.98萬

    帶全景攝像頭的車型:8.59萬的手動尊榮型和9.39萬的自動豪雅型

    編者點評:元的圖像四角拼接自然,但其他方面有較明顯的畸變。還好的是這兩款車型同樣具有前後駐車雷達。

    動力方面,元有1.5L和1.5T發動機可選,1.5L發動機最大輸出109馬力和145牛米,而1.5T則是154馬力和240牛米。其中,與1.5L發動機匹配的有5擋手動和6擋雙離合變速箱,而1.5T只有6擋雙離合變速箱。

    一眼望去元的內飾,會有種逼死處女座的感覺,特別是座椅上那條橙色的橫條,更像是為了設計而設計的。中控兩側凸起的銀色裝飾條顯得並不友好,甚至有點突兀。兩側旋風式的出風口倒是挺時尚。

    編者總結

    全景攝像頭曾經只在豪車上會有配置,不過隨着國產車的雄起,已經越來越多車型將其納入自身的“軍備庫”中,提升競爭力。誠然在一些車型上的精度依舊不高,但是有總好過沒有,而且隨着時間的推移,全景攝像肯定會被設置得更加清晰,同時價格還有望進一步下探。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • .Net Core微服務入門全紀錄(二)——Consul-服務註冊與發現(上)

    .Net Core微服務入門全紀錄(二)——Consul-服務註冊與發現(上)

    前言

    上一篇【.Net Core微服務入門全紀錄(一)——項目搭建】講到要做到服務的靈活伸縮,那麼需要有一種機制來實現它,這個機制就是服務註冊與發現。當然這也並不是必要的,如果你的服務實例很少,並且很穩定,那麼就沒有必要使用服務註冊與發現。

    服務註冊與發現

    • 服務註冊:簡單理解,就是有一個註冊中心,我們的每個服務實例啟動時,都去註冊中心註冊一下,告訴註冊中心我的地址,端口等信息。同樣的服務實例要刪除時,去註冊中心刪除一下,註冊中心負責維護這些服務實例的信息。
    • 服務發現:既然註冊中心維護了各個服務實例的信息,那麼客戶端通過註冊中心就很容易發現服務的變化了。

    有了服務註冊與發現,客戶端就不用再去配置各個服務實例的地址,改為從註冊中心統一獲取。
    那註冊中心又是怎麼保證每個地址的可用狀態呢,假如某個實例掛了怎麼辦呢?原則上掛掉的實例不應該被客戶端獲取到,所以就要提到:健康檢查 。

    • 健康檢查:每個服務都需要提供一個用於健康檢查的接口,該接口不具備業務功能。服務註冊時把這個接口的地址也告訴註冊中心,註冊中心會定時調用這個接口來檢測服務是否正常,如果不正常,則將它移除,這樣就保證了服務的可用性。

    常見註冊中心有 Consul、ZooKeeper、etcd、Eureka。

    Consul

    Consul官網:https://www.consul.io/
    Consul的主要功能有服務註冊與發現、健康檢查、K-V存儲、多數據中心等。

    • Consul安裝:很簡單,直接在官網下載解壓即可。
    • Consul運行:在consul.exe目錄下打開命令行執行 consul.exe agent -dev
    • 瀏覽器訪問:http://localhost:8500/

      Consul已成功運行。

    服務註冊

    • 首先Nuget安裝一下Consul:

      這個類庫里封裝了Consul的api操作,方便我們直接使用。當然自己去寫http調用Consul的接口也不是不行。。。接口說明:https://www.consul.io/api-docs

    • 改造一下訂單服務的代碼:

    ConsulHelper.cs:

        public static class ConsulHelper
        {
            /// <summary>
            /// 服務註冊到consul
            /// </summary>
            /// <param name="app"></param>
            /// <param name="lifetime"></param>
            public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IConfiguration configuration, IHostApplicationLifetime lifetime) 
            {
                var consulClient = new ConsulClient(c =>
                {
                    //consul地址
                    c.Address = new Uri(configuration["ConsulSetting:ConsulAddress"]);
                });
    
                var registration = new AgentServiceRegistration()
                {
                    ID = Guid.NewGuid().ToString(),//服務實例唯一標識
                    Name = configuration["ConsulSetting:ServiceName"],//服務名
                    Address = configuration["ConsulSetting:ServiceIP"], //服務IP
                    Port = int.Parse(configuration["ConsulSetting:ServicePort"]),//服務端口 因為要運行多個實例,端口不能在appsettings.json里配置,在docker容器運行時傳入
                    Check = new AgentServiceCheck()
                    {
                        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啟動多久后註冊
                        Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔
                        HTTP = $"http://{configuration["ConsulSetting:ServiceIP"]}:{configuration["ConsulSetting:ServicePort"]}{configuration["ConsulSetting:ServiceHealthCheck"]}",//健康檢查地址
                        Timeout = TimeSpan.FromSeconds(5)//超時時間
                    }
                };
    
                //服務註冊
                consulClient.Agent.ServiceRegister(registration).Wait();
    
                //應用程序終止時,取消註冊
                lifetime.ApplicationStopping.Register(() =>
                {
                    consulClient.Agent.ServiceDeregister(registration.ID).Wait();
                });
    
                return app;
            }
        }
    

    appsettings.json:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "ConsulSetting": {
        "ServiceName": "OrderService",
        "ServiceIP": "localhost",
        "ServiceHealthCheck": "/healthcheck",
        "ConsulAddress": "http://host.docker.internal:8500"//注意,docker容器內部無法使用localhost訪問宿主機器,如果是控制台啟動的話就用localhost
      }
    }
    

    Startup.cs:

        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseRouting();
    
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
    
                //服務註冊
                app.RegisterConsul(Configuration, lifetime);
            }
        }
    

    OrdersController.cs:

        [Route("[controller]")]
        [ApiController]
        public class OrdersController : ControllerBase
        {
            private readonly ILogger<OrdersController> _logger;
            private readonly IConfiguration _configuration;
    
            public OrdersController(ILogger<OrdersController> logger, IConfiguration configuration)
            {
                _logger = logger;
                _configuration = configuration;
            }
    
            [HttpGet]
            public IActionResult Get()
            {
                string result = $"【訂單服務】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}——" +
                    $"{Request.HttpContext.Connection.LocalIpAddress}:{_configuration["ConsulSetting:ServicePort"]}";
                return Ok(result);
            }
        }
    

    HealthCheckController.cs:

        [Route("[controller]")]
        [ApiController]
        public class HealthCheckController : ControllerBase
        {
            /// <summary>
            /// 健康檢查接口
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public IActionResult Get()
            {
                return Ok();
            }
        }
    

    至此就完成了服務註冊,取消註冊,健康檢查等功能的代碼編寫。

    • 同樣的改造一下產品服務,代碼差不多一樣,就不貼了。

    運行服務

    繼續在docker中運行服務實例,不習慣docker的話用控制台啟動也行。–ConsulSetting:ServicePort參數就是傳入容器的端口信息。

    docker build -t orderapi:1.0 -f ./Order.API/Dockerfile .
    docker run -d -p 9060:80 --name orderservice orderapi:1.0 --ConsulSetting:ServicePort="9060"
    docker run -d -p 9061:80 --name orderservice1 orderapi:1.0 --ConsulSetting:ServicePort="9061"
    docker run -d -p 9062:80 --name orderservice2 orderapi:1.0 --ConsulSetting:ServicePort="9062"
    
    docker build -t productapi:1.0 -f ./Product.API/Dockerfile .
    docker run -d -p 9050:80 --name productservice productapi:1.0 --ConsulSetting:ServicePort="9050"
    docker run -d -p 9051:80 --name productservice1 productapi:1.0 --ConsulSetting:ServicePort="9051"
    docker run -d -p 9052:80 --name productservice2 productapi:1.0 --ConsulSetting:ServicePort="9052"
    

    至此,6個服務器實例都已運行,並且成功註冊到Consul。

    隨便停止2個服務:

    可以看到停止的服務已經在Consul中被移除。注意,這個是我們停止程序時主動調用Consul移除的。

    //應用程序終止時,取消註冊
    lifetime.ApplicationStopping.Register(() =>
    {
        consulClient.Agent.ServiceDeregister(registration.ID).Wait();
    });
    

    當然程序發生異常,健康檢查不能正確響應的話,Consul也會移除,有一點區別。

    那麼註冊,發現,健康檢查功能都完成了,下一步就該考慮客戶端如何拿到這些服務實例的地址了。

    代碼放在:https://github.com/xiajingren/NetCoreMicroserviceDemo

    未完待續…

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 波蘭擬立法禁止生產皮草 引發業者抗議

    摘錄自2020年9月17日中央社報導

    波蘭動物皮草農場主人和猶太潔食肉品製造業者今(16日)在首都華沙抗議一項正在國會闖關的新法,這項法案受到動物維權團體支持。

    法新社報導,根據動物維權人士說法,波蘭是全球第3大皮草生產國,僅次於中國和丹麥,此外,波蘭也是將猶太潔食肉品外銷到以色列和歐洲猶太社區的重要出口國。

    這項立法將禁止業者透過畜養動物來獲取皮草,並禁止出口按伊斯蘭教律法及猶太律法處理的肉品。

    這項立法上週首度遭到擱置時,執政法律正義黨黨魁卡臣斯基(Jaroslaw Kaczynski)表示:「波蘭對於動物的標準應該不比西方國家差,甚至應該更好。」

    生物多樣性
    國際新聞
    波蘭
    動物皮草
    立法

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 買毛線飛度捷達!9萬就有高顏值省油SUV了!

    買毛線飛度捷達!9萬就有高顏值省油SUV了!

    雖然是定位年輕,但內飾除了配色之外就看不出有多個性,中規中矩就像大眾,哦,還是比大眾要靈活一些。斑馬系統還是很棒棒的,和目前那些什麼“天貓精靈”有異曲同工之妙,一句話能夠解決的問題,很多人可能還是習慣按鍵。

    10萬買什麼車?飛度啊!還用問?

    這樣的問答非常“知乎”。

    然而,這種“知乎”風格的回答只適合一部分人,你看,飛度一個月也就賣幾千台。其實10萬可以買的車很多,如果你想買“飛度”那樣省油大空間的,也有不少選擇,譬如今天我們視頻的主角,榮威RX3。

    RX3採用家族的“律動”設計,雖然談不上多驚艷,但目前這套設計在榮威RX5、i6上表現良好,市場接受度高,就像是大眾的風格那樣,為人們廣泛接受。

    雖然是定位年輕,但內飾除了配色之外就看不出有多個性,中規中矩就像大眾,哦,還是比大眾要靈活一些。

    斑馬系統還是很棒棒的,和目前那些什麼“天貓精靈”有異曲同工之妙,一句話能夠解決的問題,很多人可能還是習慣按鍵。

    1.6L阿特金森循環發動機主打燃油經濟性,配合上來自愛信的CVT變速箱,整體表現能夠滿足日常的使用,發動機輸出線性,符合這個排量發動機的表現。

    加減速測試

    至於駕駛感受方面,這台車挺日系的,怎麼說呢,一方面,懸挂偏軟,動力偏線性;另一方面,追求低油耗,不盲目追求性能。

    總結

    榮威RX3作為一款新生代車型,無論是外觀設計還是內飾做工都做到了這個級別的前列,並且1.6L+CVT的動力組合更加適合城市中穿梭,如果你的駕駛習慣是溫和的,沒有太多的動力需求,僅僅作為代步的話,榮威RX3值得你留意。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • Kubernetes-subpath的使用

    一、什麼是subpath

    為了支持單一個pod多次使用同一個volume而設計,subpath翻譯過來是子路徑的意思,如果是數據卷掛載在容器,指的是存儲卷目錄的子路徑,如果是配置項configMap/Secret,則指的是掛載在容器的子路徑。

     

    二、subpath的使用場景

    1、 1個pod中可以拉起多個容器,有時候希望將不同容器的路徑掛載在存儲卷volume的子路徑,這個時候需要用到subpath

    2、volume支持將configMap/Secret掛載在容器的路徑,但是會覆蓋掉容器路徑下原有的文件,如何支持選定configMap/Secret的每個key-value掛載在容器中,且不會覆蓋掉原目錄下的文件,這個時候也可以用到subpath

     

    三、subpath的使用

    1、存儲卷

        採用hostpath的方式創建PV,宿主機的映射目錄為/data/pod/volume5

    [root@k8s-master zhanglei]# cat pv-subpath.yaml 
    kind: PersistentVolume
    apiVersion: v1
    metadata:
      name: pv-subpath-05
      labels:
        release: stable
    spec:
      capacity:
        storage: 0.1Gi
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Recycle
      hostPath:
        path: /data/pod/volume5                 # 宿主機的目錄

    [root@k8s-master zhanglei]# kubectl create -f pv-subpath.yaml  

    PV創建成功后,再創建PVC

    [root@k8s-master zhanglei]# cat pvc-subpath.yaml 
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc-subpath
      namespace: default
    spec:
     accessModes: ["ReadWriteOnce"]
     resources:
       requests: 
         storage: 0.05Gi
    [root@k8s-master zhanglei]# kubectl create -f pvc-subpath.yaml

    在pod中聲明並使用subpath

    [root@k8s-master zhanglei]# cat pod-subpath.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-subpath-zltest
    spec:
        containers:
        - name: ubuntu-subpath-container
          image: ubuntu
          volumeMounts:
          - mountPath: /var/lib/ubuntu            # 容器1的掛載目錄
            name: subpath-vol
            subPath: ubuntutest                   # 宿主機volume5的子目錄1
        - name: nginx-subpath-container
          image: nginx
          volumeMounts:
          - mountPath: /var/www/nginx             # 容器2的掛載目錄
            name: subpath-vol
            subPath: nginxtest                   # 宿主機volume5的子目錄2 
        volumes:
        - name: subpath-vol
          persistentVolumeClaim:
            claimName: pvc-subpath               # PVC的名字

      [root@k8s-master zhanglei]# kubectl create -f pod-subpath.yaml

    [root@k8s-master zhanglei]# kubectl describe pod  pod-subpath-zltest 
    Name:         pod-subpath-zltest
    Namespace:    default
    Priority:     0
    Node:         k8s-master/192.168.126.129
    Start Time:   Fri, 29 May 2020 16:45:49 +0800
    Labels:       <none>
    Annotations:  cni.projectcalico.org/podIP: 10.122.235.235/32
                  cni.projectcalico.org/podIPs: 10.122.235.235/32
    Status:       Running
    IP:           10.122.235.235
    IPs:
      IP:  10.122.235.235
    Containers:
      ubuntu-subpath-container:
        Container ID:   docker://6e5cb30ee7e03b77d2ca22e4cd818ff326fa40836427fe17b1584646b4388dce
        Image:          ubuntu
        Image ID:       docker-pullable://ubuntu@sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7
        Port:           <none>
        Host Port:      <none>
        State:          Waiting
          Reason:       CrashLoopBackOff
        Last State:     Terminated
          Reason:       Completed
          Exit Code:    0
          Started:      Sun, 14 Jun 2020 22:38:11 +0800
          Finished:     Sun, 14 Jun 2020 22:38:11 +0800
        Ready:          False
        Restart Count:  558
        Environment:    <none>
        Mounts:
          /var/lib/ubuntu from subpath-vol (rw,path="ubuntutest")
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
      nginx-subpath-container:
        Container ID:   docker://95101741eb1b6aa4c1e53d8fc4ab8006e74fd2eb923eca211ca20a01edcd7630
        Image:          nginx
        Image ID:       docker-pullable://nginx@sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
        Port:           <none>
        Host Port:      <none>
        State:          Running
          Started:      Fri, 29 May 2020 16:47:14 +0800
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
          /var/www/nginx from subpath-vol (rw,path="nginxtest")
    Conditions:
      Type              Status
      Initialized       True 
      Ready             False 
      ContainersReady   False 
      PodScheduled      True 
    Volumes:
      subpath-vol:
        Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
        ClaimName:  pvc-subpath
        ReadOnly:   false
      default-token-74s86:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-74s86
        Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  <none>
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
    Events:
      Type     Reason   Age                    From                 Message
      ----     ------   ----                   ----                 -------
      Normal   Pulled   21m (x555 over 16d)    kubelet, k8s-master  Successfully pulled image "ubuntu"
      Normal   Created  21m (x555 over 16d)    kubelet, k8s-master  Created container ubuntu-subpath-container
      Normal   Started  21m (x555 over 16d)    kubelet, k8s-master  Started container ubuntu-subpath-container
      Normal   Pulling  6m10s (x562 over 16d)  kubelet, k8s-master  Pulling image "ubuntu"
      Warning  BackOff  71s (x11744 over 16d)  kubelet, k8s-master  Back-off restarting failed container

    現在來驗證下在宿主機存儲卷的目錄下是否有2個子目錄,1個是ubuntutest用來掛載容器1的,另外1個是nginxtest用來掛載容器2的

    [root@k8s-master /]# cd data/pod/volume5
    [root@k8s-master volume5]# ls
    nginxtest ubuntutest
    [root@k8s-master volume5]# cd nginxtest/     # 可以看到是1個目錄,非文件
    [root@k8s-master nginxtest]#

    進入到容器中,掛載一個文件,驗證是否可以同步到存儲卷

    [root@k8s-master nginxtest]# kubectl exec -it pod-subpath-zltest -c nginx-subpath-container -- bash
    root@pod-subpath-zltest:/# cd /var/www/nginx
    root@pod-subpath-zltest:/var/www/nginx# ls
    nginx-test-subpath.txt
    [root@k8s-master volume5]# cd nginxtest/
    [root@k8s-master nginxtest]# ls
    nginx-test-subpath.txt

    可以看到容器1的目錄/var/www/nginx 和存儲卷的子目錄 nginxtest完成了映射,容器2類似,這裏不再贅述。

    2、配置項-configMap

    1)創建configMap

    [root@k8s-master consecret]# cat conf-subpath.yaml 
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: conf-subpath-zltest
      namespace: default
    data:
      example.property.1: hello      # key-value鍵值對
      example.property.2: world
      example.property.file: |-
        property.1=value-1
        property.2=value-2
        property.3=value-3

    2)在Pod中使用configMap

    [root@k8s-master consecret]# cat pod-conf-subpath.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        purpose: test-configmap-volume
      name: pod-conf-testvolume
    spec:
      containers:
        - name: test-configmap-volume
          image: nginx
          volumeMounts:
            - name: config-volume
              mountPath: /etc/nginx/example.property.1       # 容器掛載目錄
              subPath: example.property.1                    # 將key名稱作為文件名,hello作為文件內容
      volumes:
        - name: config-volume
          configMap:
             name: conf-subpath-zltest      # 指定使用哪個CM
            
    [root@k8s-master consecret]# kubectl create -f pod-conf-subpath.yaml 
    [root@k8s-master consecret]# kubectl describe pod  pod-conf-testvolume 
    Name:         pod-conf-testvolume
    Namespace:    default
    Priority:     0
    Node:         k8s-master/192.168.126.129
    Start Time:   Wed, 03 Jun 2020 11:46:36 +0800
    Labels:       purpose=test-configmap-volume
    Annotations:  cni.projectcalico.org/podIP: 10.122.235.249/32
                  cni.projectcalico.org/podIPs: 10.122.235.249/32
    Status:       Running
    IP:           10.122.235.249
    IPs:
      IP:  10.122.235.249
    Containers:
      test-configmap-volume:
        Container ID:   docker://e2cf37cb24af32023eb5d22389545c3468104a4344c47363b5330addc40cb914
        Image:          nginx
        Image ID:       docker-pullable://nginx@sha256:883874c218a6c71640579ae54e6952398757ec65702f4c8ba7675655156fcca6
        Port:           <none>
        Host Port:      <none>
        State:          Running
          Started:      Wed, 03 Jun 2020 11:46:53 +0800
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /etc/nginx/example.property.1 from config-volume (rw,path="example.property.1")  
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             True 
      ContainersReady   True 
      PodScheduled      True 
    Volumes:
      config-volume:
        Type:      ConfigMap (a volume populated by a ConfigMap)
        Name:      conf-subpath-zltest
        Optional:  false
      default-token-74s86:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-74s86
        Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  <none>
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
    Events:          <none>

    在容器掛載路徑驗證下是否將configMap中example.property.1掛載在容器中,且是否會覆蓋掉原有的目錄

    root@pod-conf-testvolume:/# cd  /etc/nginx 
    root@pod-conf-testvolume:/etc/nginx# ls
    conf.d            fastcgi_params  koi-win    modules     scgi_params   win-utf
    example.property.1  koi-utf        mime.types    nginx.conf  uwsgi_params

    從上可以看到example.property.1已經掛載到容器中,且未對目錄原有的文件進行覆蓋

    root@pod-conf-testvolume:/etc/nginx# cd example.property.1 
    bash: cd: example.property.1: Not a directory
    root@pod-conf-testvolume:/etc/nginx# cat example.property.1 helloroot@pod-conf-testvolume:/etc/nginx# 

    從上可以驗證configMap的subpath用法支持將configMap中的每對key-value以key名稱作為文件名,value作為文件內容掛載到容器的目錄中。

    四、總結

    本文介紹了subpath分別在持久化存儲卷和配置項configMap中的使用,豐富了volume在pod中的使用場景。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 【asp.net core 系列】9 實戰之 UnitOfWork以及自定義代碼生成

    【asp.net core 系列】9 實戰之 UnitOfWork以及自定義代碼生成

    0. 前言

    在前一篇中我們創建了一個基於EF的數據查詢接口實現基類,這一篇我將帶領大家講一下為這EF補充一些功能,並且提供一個解決避免寫大量配置類的方案。

    1. SaveChanges的外移

    在之前介紹EF Core的時候,我們提到過使用EF需要在每次使用之後,調用一次SaveChanges將數據提交給數據庫。在實際開發中,我們不能添加一條數據或者做一次修改就調用一次SaveChanges,這完全不現實。因為每次調用SaveChanges是EF向數據庫提交變更的時候,所以EF推薦的是每次執行完用戶的請求之後統一提交數據給數據庫。

    這樣就會造成一個問題,可能也不是問題:我們需要一個接口來管理EF 的SaveChanges操作。

    1.1 創建一個IUnitOfWork接口

    通常我們會在Domain項目中添加一個IUnitOfWork接口,這個接口有一個方法就是SaveChanges,代碼如下:

    namespace Domain.Insfrastructure
    {
        public interface IUnitOfWork
        {
            void SaveChanges();
        }
    }
    

    這個方法的意思表示到執行該方法的時候,一個完整的工作流程執行完成了。也就是說,當執行該方法后,當前請求不會再與數據庫發生連接。

    1.2 實現IUnitOfWork接口

    在 Domain.Implement中添加IUnitOfWork實現類:

    using Domain.Insfrastructure;
    using Microsoft.EntityFrameworkCore;
    
    namespace Domain.Implements.Insfrastructure
    {
        public class UnitOfWork: IUnitOfWork
        {
            private DbContext DbContext;
            public UnitOfWork(DbContext context)
            {
                DbContext = context;
            }
    
            public void SaveChanges()
            {
                DbContext.SaveChanges();
            }
        }
    }
    

    1.3 調用時機

    到現在我們已經創建了一個UnitOfWork的方法,那麼問題來了,我們該在什麼時候調用呢,或者說如何調用呢?

    我的建議是創建一個ActionFilter,針對所有的控制器進行SaveChanges進行處理。當然了,也可以在控制器中持有一個IUnitOfWork的示例,然後在Action結束的時候,執行SaveChanges。不過這樣存在一個問題,可能會存在遺漏的方法。所以我推薦這樣操作,這裏簡單演示一下如何創建攔截器:

    在Web的根目錄下,創建一個Filters目錄,這個目錄里用來存儲一些過濾器,創建我們需要的過濾器:

    using Domain.Insfrastructure;
    using Microsoft.AspNetCore.Mvc.Filters;
    
    namespace Web.Filters
    {
        public class UnitOfWorkFilterAttribute : ActionFilterAttribute
        {
            public IUnitOfWork UnitOfWork;
    
            public override void OnActionExecuted(ActionExecutedContext context)
            {
                UnitOfWork.SaveChanges();
            }
        }
    }
    

    使用一個ActionFilter可以很方便的解決一些容易遺漏但又必須執行的代碼。這裏就先不介紹如何配置Filter的啟用和詳細介紹了,請允許我賣個關子。當然了,有些小夥伴肯定也能猜到這是一個Attribute類,所以可以按照Attribute給Controller打標記。

    2. 創建一個簡單的代碼生成方法

    之前在介紹EF的時候,有個小夥伴跟我說,還要寫配置文件啊,太麻煩了。是的,之前我介紹了很多關於寫配置文件不使用特性的好處,但不解決這個問題就無法真正體檢配置類的好處。

    雖然說,EF Core約定優先,但是如果默認約定的話,得在DBContext中聲明 DbSet<T> 來聲明這個字段,實體類少的話,比較簡單。如果多個數據表的話,就會非常麻煩。

    所以這時候就要使用工具類, 那麼簡單的分析一下,這個工具類需要有哪些功能:

    • 第一步,找到實體類並解析出實體類的類名
    • 第二步,生成配置文件
    • 第三步,創建對應的Repository接口和實現類

    很簡單的三步,但是難點就是找實體類並解析出實體類名。

    在Util項目中添加一個Develop目錄,並創建Develop類:

    namespace Utils.Develop
    {
        public class Develop
        {
            
        }
    }
    

    定位當前類所在目錄,通過

    Directory.GetCurrentDirectory()
    

    這個方法可以獲取當前執行的DLL所在目錄,當然不同的編譯器在執行的時候,會有微妙的不同。所以我們需要以此為根據然後獲取項目的根目錄,一個簡單的方法,查找*.sln 所在目錄:

    public static string CurrentDirect
    {
        get
        {
            var execute = Directory.GetCurrentDirectory();
            var parent = Directory.GetParent(execute);
            while(parent.GetFiles("*.sln",SearchOption.TopDirectoryOnly).Length == 0)
            {
                parent = parent.Parent;
                if(parent == null)
                {
                    return null;
                }
            }
            return parent.FullName;
        }
    }
    

    2.1 獲取實體類

    那麼獲取到根目錄之後,我們下一步就是獲取實體類。因為我們的實體類都要求是繼承BaseEntity或者命名空間都是位於Data.Models下面。當然這個名稱都是根據實際業務場景約束的,這裏只是以當前項目舉例。那麼,我們可以通過以下方法找到我們設置的實體類:

    public static Type[] LoadEntities()
    {
        var assembly = Assembly.Load("Data");
        var allTypes = assembly.GetTypes();
        var ofNamespace = allTypes.Where(t => t.Namespace == "Data.Models" || t.Namespace.StartsWith("Data.Models."));
        var subTypes = allTypes.Where(t => t.BaseType.Name == "BaseEntity`1");
        return ofNamespace.Union(subTypes).ToArray();
    }
    

    通過 Assembly加載Data的程序集,然後選擇出符合我們要求的實體類。

    2.2 編寫Repository接口

    我們先約定Model的Repository接口定義在 Domain/Repository目錄下,所以它們的命名空間應該是:

    namespace Domain.Repository	
    {
    }
    

    假設目錄情況與Data/Models下面的代碼結構保持一致,然後生成代碼應該如下:

    public static void CreateRepositoryInterface(Type type)
    {
        var targetNamespace = type.Namespace.Replace("Data.Models", "");
        if (targetNamespace.StartsWith("."))
        {
            targetNamespace = targetNamespace.Remove(0);
        }
        var targetDir = Path.Combine(new[]{CurrentDirect,"Domain", "Repository"}.Concat(
            targetNamespace.Split('.')).ToArray());
        if (!Directory.Exists(targetDir))
        {
            Directory.CreateDirectory(targetDir);
        }
    
        var baseName = type.Name.Replace("Entity","");
    
        if (!string.IsNullOrEmpty(targetNamespace))
        {
            targetNamespace = $".{targetNamespace}";
        }
        var file = $"using {type.Namespace};\r\n"
            + $"using Domain.Insfrastructure;\r\n"
            + $"namespace Domain.Repository{targetNamespace}\r\n"
            + "{\r\n"
            + $"\tpublic interface I{baseName}ModifyRepository : IModifyRepository<{type.Name}>\r\n" +
            "\t{\r\n\t}\r\n"
            + $"\tpublic interface I{baseName}SearchRepository : ISearchRepository<{type.Name}>\r\n" +
            "\t{\r\n\t}\r\n}";
    
        File.WriteAllText(Path.Combine(targetDir, $"{baseName}Repository.cs"), file);
    }
    
    

    2.3 編寫Repository的實現類

    因為我們提供了一個基類,所以我們在生成方法的時候,推薦繼承這個類,那麼實現方法應該如下:

    public static void CreateRepositoryImplement(Type type)
    {
        var targetNamespace = type.Namespace.Replace("Data.Models", "");
        if (targetNamespace.StartsWith("."))
        {
            targetNamespace = targetNamespace.Remove(0);
        }
    
        var targetDir = Path.Combine(new[] {CurrentDirect, "Domain.Implements", "Repository"}.Concat(
            targetNamespace.Split('.')).ToArray());
        if (!Directory.Exists(targetDir))
        {
            Directory.CreateDirectory(targetDir);
        }
        var baseName = type.Name.Replace("Entity", "");
        if (!string.IsNullOrEmpty(targetNamespace))
        {
            targetNamespace = $".{targetNamespace}";
        }
    
        var file = $"using {type.Namespace};" +
            $"\r\nusing Domain.Implements.Insfrastructure;" +
            $"\r\nusing Domain.Repository{targetNamespace};" +
            $"\r\nusing Microsoft.EntityFrameworkCore;" +
            $"namespace Domain.Implements.Repository{targetNamespace}\r\n" +
            "{" +
            $"\r\n\tpublic class {baseName}Repository :BaseRepository<{type.Name}> ,I{baseName}ModifyRepository,I{baseName}SearchRepository " +
            "\r\n\t{" +
            $"\r\n\t\tpublic {baseName}Repository(DbContext context) : base(context)"+
            "\r\n\t\t{"+
            "\r\n\t\t}\r\n"+
            "\t}\r\n}";
        File.WriteAllText(Path.Combine(targetDir, $"{baseName}Repository.cs"), file);
    }
    

    2.4 配置文件的生成

    仔細觀察一下代碼,可以發現整體都是十分簡單的。所以這篇就不掩飾如何生成配置文件了,小夥伴們可以自行嘗試一下哦。具體實現可以等一下篇哦。

    3. 總結

    這一篇初略的介紹了兩個用來輔助EF Core實現的方法或類,這在開發中很重要。UnitOfWork用來確保一次請求一個工作流程,簡單的代碼生成類讓我們能讓我們忽略那些繁重的創建同類代碼的工作。

    更多內容煩請關注我的博客《高先生小屋》

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 中國湖北化工廠大爆炸 至少5死1傷

    摘錄自2020年9月28日自由時報報導

    中國湖北省天門市岳口鎮譚湖工業園區內一化工廠,今(28)日下午發生爆炸,現場黃煙亂竄疑似硝酸外洩,當地政府部門指出,目前事故已造成5死1傷。

    綜合中媒報導,湖北省應急管理廳指出,天門市應急管理局報告,今日下午2點15分左右,天門市岳口工業園天門楚天精細化工有限公司進行設備調試期間,發生板框壓力機爆炸,初步發現事故現場5人死亡、1人受傷。有目擊者稱現場疑似是硝酸外洩,導致竄出大量黃煙。

    天門市應急管理局表示,傷者已送醫救治,現場搜救工作仍在進行中,事故原因及過程仍有待釐清。

    污染治理
    國際新聞
    中國
    化工廠
    化工廠爆炸

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • Golang簡單入門教程——函數進階篇

    Golang簡單入門教程——函數進階篇

    本文始發於個人公眾號:TechFlow,原創不易,求個關注

    今天是golang專題的第八篇,我們來聊聊golang當中的函數。

    我們在之前的時候已經介紹過了函數的基本用法,知道了怎麼樣設計或者是定義一個函數,以及怎麼樣調用一個函數,還了解了defer的用法。今天這篇文章我們來繼續深入這個話題,來看看golang當中關於函數的一些進階的用法。

    返回error

    前文當中我們曾經提到過,在golang當中並沒有try catch捕獲異常的機制。在其他語言當中異常只有一種,可以通過try catch語句進行捕獲,而golang當中做了區分,將異常分為兩種,一種是可以在函數當中返回的error,另外一種是嚴重的會引起程序崩潰的panic

    在golang中,error也是一個數據類型,由於golang支持函數的多值返回,所以我們可以設置一個返回值是error。我們通過對這個error的判斷來獲取運行函數的情況。

    舉個例子,比如說,假設我們實現一個Divide函數實現兩個int相除。那麼顯然我們需要除數不能為0,當除數為0的時候我們需要返回一個異常。這個時候我們可以把代碼寫成這樣:

    // Divide test
    func Divide(a, b int) (ret int, err error) {
     if b == 0 {
      err = errors.New("divisor is zero")
      return
     }
     return a / b, nil
    }
    

    當我們調用函數的時候,我們用兩個變量去接收這個函數返回的結果,第二個變量的類型是error。當這個函數成功執行的時候第二個變量的結果為nil,我們只需要判斷它是否等於nil,就可以知道函數執行是否成功。如果不成功,我們還可以記錄失敗的原因。

    func main() {
     ret, err := Divide(5, 2)
     if err == nil {
      fmt.Println(ret)
     } else {
      fmt.Println(err)
     }
    }
    

    這種用法在golang當中非常常見,我們之前在介紹字符串相關操作的時候也介紹過返回error的用法。我們在設計函數的時候如果需要判斷輸入的合法性可以使用error,這樣就可以保證handle住非法的情況,並且也能讓下游感知到。

    不定參數

    不定參數的用法在很多語言當中都有,比如在Python當中,不定參數是*args。通過*args我們可以接受任何數量的參數,由於Python是弱變量類型的語言,所以args這些參數的類型可以互不相同。但是golang不行,golang嚴格限制類型,不定參數必須要保證類型一樣。除此之外,其他的用法和Python一樣,不定參數會以數組的形式傳入函數內部,我們可以使用數組的api進行訪問。

    我們來看一個例子,我們通過…來定義不定參數。比如我們可以實現一個sum函數,可以將任意個int進行累加。

    func Sum(nums ... int) int{
        ret := 0
        for _, num := range nums {
            ret += num
        }
        return ret
    }
    

    我們來仔細研究一下上面這個例子,在這個例子當中,我們通過…傳入了一個不定參數,我們不定參數的類型只寫一次,寫在…的後面。從底層實現的機制上來說,不定參數本質上是將傳入的參數轉化成數組的切片。但是這就有了一個問題,既然傳入的是一個數組的切片,我們為什麼要專門設置一個關鍵字,而不是規定傳入一個切片呢?

    比如上面的代碼我們完全可以寫成這樣:

    func Sum(nums []int) int{
        ret := 0
        for _, num := range nums {
            ret += num
        }
        return ret
    }
    

    無論從代碼的閱讀還是編寫上來看相差並不大,好像這樣做完全沒有意義,其實不是這樣的。這個關鍵字簡化的並不是函數的設計方,而是函數的使用方。如果我們規定了函數的輸入是一個切片,那麼當我們在傳入數據的時候,必須要使用強制轉化,將我們的數據轉化成切片,比如這樣:

    Sum([]int(3, 4, 6, 8))
    

    而使用…關鍵字我們則可以省略掉強制轉化的過程,上面的代碼我們寫成這樣就可以了:

    Sum(3, 4, 6, 8)
    

    很明顯可以看出差異,使用不定參數的話調用方會輕鬆很多,不需要再進行額外的轉換。如果我們要傳入的也是一個數組,那麼在傳遞的時候也需要用…符號將它展開

    a := make([]int)
    a = append(a, 3)
    a = append(a, 4)
    Sum(a...)
    Sum(a[1:]...)
    

    既然聊到不定參數的傳遞,那麼又涉及到了一個問題,當我們想要像Python那樣傳遞多個類型不同的參數的時候,應該怎麼辦呢?按照道理golang是靜態類型的語言,限制死了參數的類型,是不能隨便轉換的才對。但是偏偏這樣操作是可以的,因為golang當中有一個特殊的類型,叫做interface

    interface的用法很多,一個很重要的用法是用在面向對象當中充當結構體的接口。這裏我們不做過多深入,我們只需要知道,interface的一個用法是可以用來代替所有類型的變量。我們來看一個例子:

    func testInterface(args ...interface{}) {
        for _, arg := range args {
            switch arg.(type) {
                case int:
                 fmt.Println("it's a int")
             case string:
                 fmt.Println("it's a string")    
                case float32:
                 fmt.Println("it's a float")
                default:
                 fmt.Println("it's an unknown type")
            }
        }
    }
    
    
    func main() {
        testInterface(3, 4.5, "abc")
    }
    

    我們可以用.(type)獲取一個interface變量實際的類型,這樣我們就實現了任意類型任意數量參數的傳入。

    匿名函數和閉包

    匿名函數我們在Python當中經常使用到,其實這個概念出現已久,最早可以追溯到1958年Lisp語言。所以這並不是一個新鮮的概念,只是傳統的C、C++等語言沒有支持匿名函數的功能,所以顯得好像是一個新出現的概念一樣。golang當中也支持匿名函數,但是golang當中匿名函數的使用方式和Python等語言稍稍有些不同。

    在Python當中我們是通過lambda關鍵字來定義匿名函數,它可以被傳入另一個函數當中,也可以賦值給一個變量。golang當中匿名函數的定義方式和普通函數基本是一樣的,只是沒有函數名而已,不過它也可以被傳入函數或者是賦值給另一個變量。

    比如:

    s := func(a, b int) int {
        return a + b
    }
    
    c := s(3, 4)
    

    除了匿名函數之外,golang還支持閉包。閉包的概念我們在之前Python閉包的介紹當中曾經提到過,我們之前也用過好幾次,閉包的本質不是一個包,而是一個函數,是一個持有外部環境變量的函數。比如在Python當中,我們經常可以看到這樣的寫法:

    def outside(x):
        def inside(y):
            print(x, y)
        return inside
    
    
    ins = outside(3)
    ins(5) #3, 5
    

    我們可以看到outside這個函數返回了inside這個函數,對於inside這個函數而言,它持有了x這個變量。x這個變量並不是屬於它的,而是定義在它的外部域的。並且我們在調用inside的時候是無法干涉這個變量的,這就是一個閉包的典型例子。根據輪子哥的說法,閉包的閉的意思並不是封閉內部,而是封閉外部。當外部scope失效的時候,函數仍然持有一份外部的環境的值。

    golang當中閉包的使用方法大同小異,我們來看一個類似的例子:

    func main() {
        a := func(x int) (func(int)) {
            return func(y int){
                fmt.Println(x, y)
            }
        }
        b := a(4)
        b(5)
    }
    

    這個閉包的例子和剛才上面Python那個例子是一樣的,唯一不同的是由於golang是強類型的語言,所以我們需要在定義閉包的時候將輸入和輸出的類型定義清楚。

    總結

    關於golang當中函數的高級用法就差不多介紹完了,這些都是實際編程當中經常使用的方法,如果想要學好golang這門語言的話,這些是基本功。如果你之前有其他語言的基礎,來寫go的話,整體上手的難度還是不大的,很多設計都可以在其他的語言當中找到影子,有了參照來學會簡單得多。

    我很難描述實際工作當中寫golang的體驗,和我寫任何一門其他的語言都不一樣,有一種一開始期望很低,慢慢慢慢總能發現驚喜的感覺。我強烈建議大家去實際感受一下。

    如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

    本文使用 mdnice 排版

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 【SEED Labs】Public-Key Infrastructure (PKI) Lab

    【SEED Labs】Public-Key Infrastructure (PKI) Lab

    Lab Overview

    公鑰加密是當今安全通信的基礎,但當通信的一方向另一方發送其公鑰時,它會受到中間人的攻擊。根本的問題是,沒有簡單的方法來驗證公鑰的所有權,即,給定公鑰及其聲明的所有者信息,如何確保該公鑰確實屬於聲明的所有者?公鑰基礎設施(PKI)是解決這一問題的一種切實可行的方法。

    通過這個實驗,我們應該能夠更好地了解PKI是如何工作的,PKI是如何用來保護網絡,以及PKI如何打敗中間人攻擊。此外,我們將能夠了解在公鑰基礎設施中信任的根源,以及如果這種根源信任被破壞會出現什麼問題。本實驗所涵蓋的主題如下:

    • Public-key encryption

    • Public-Key Infrastructure (PKI)

    • Certificate Authority (CA) and root CA

    • X.509 certificate and self-signed certificate

    • Apache, HTTP, and HTTPS

    • Man-in-the-middle attacks

    Lab Environment

    這個實驗在我kali VM和Ubuntu 16.04 VM上進行了測試.在這個實驗中,我們將使用openssl命令和庫。

    Lab Tasks

    Task1: Becoming a Certificate Authority(CA) 

    證書頒發機構(CA)是發布数字證書的受信任實體。数字證書通過證書的命名主體來驗證公鑰的所有權。一些商業性的CAs被視為根類CAs;在撰寫本文時,VeriSign是最大的CA。想要獲得商業核證機關發出的数字證書的用戶需要向這些核證機關支付費用。

    在這個實驗室,我們需要創建数字證書,但是我們不會支付任何商業CA,我們自己會成為一個根CA,然後用這個CA為其他人(比如服務器)頒發證書。在這個任務中,我們將使自己成為一個根CA,併為這個CA生成一個證書。RootCA的認證通常預裝在大多數操作系統、web瀏覽器和其他依賴於PKI的軟件中。根CA的證書是無條件信任的。

    The Configuration File openssl.conf  

    為了使用OpenSSL創建證書,必須有一個配置文件。配置文件通常有一個extension.cnf。它由三個OpenSSL命令使用:ca、req和x509。可以使用谷歌搜索找到openssl.conf的手冊頁。還可以從/usr/lib/ssl/openssl.cnf獲得配置文件的副本。將此文件複製到當前目錄后,需要按照配置文件中指定的方式創建子目錄(查看[CA default]部分): 

     

     

     對於index.txt文件,只需創建一個空文件。對於serial文件,在文件中放入一個字符串格式的数字(例如1000)。設置好配置文件openssl.cnf之後,就可以創建和頒發證書了。

    CertificateAuthority(CA).

    如前所述,我們需要為我們的CA生成一個自簽名證書,這意味着這個CA是完全可信的,它的證書將作為根證書。運行以下命令為CA生成自簽名證書:

    系統將提示您輸入信息和密碼。不要丟失此密碼,因為每次要使用此CA為其他人簽名證書時,都必須鍵入口令。您還將被要求填寫一些信息,如國家名稱、常用名稱等。該命令的輸出存儲在兩個文件中:ca.key和ca.crt。文件CA .key包含CA的私鑰,而CA .crt包含公鑰證書。

     

     

     Task2: Creating a Certificate for SEEDPKILab2018.com 

    現在,我們成為一個根CA,我們準備為我們的客戶簽署数字證書。我們的第一個客戶是一家名為SEEDPKILab2018.com的公司。該公司要從CA獲得数字證書,需要經過三個步驟。

    Step 1: Generate public/private key pair  。公司需要首先創建自己的公鑰/私鑰對。可以運行以下命令來生成RSA密鑰對(私有和公共密鑰)。您還需要提供一個密碼來加密私鑰(使用AES-128加密算法,在命令選項中指定)。密鑰將存儲在文件服務器中。

     

    server.key是一個編碼的文本文件(也是加密的),因此無法看到實際內容,例如模數、私有指數等。要查看這些,可以運行以下命令:

     

     

     

     

     Step 2: Generate a Certificate Signing Request (CSR). 一旦公司擁有了密鑰文件,它應該生成一個證書籤名請求(CSR),它基本上包括公司的公鑰。CSR將被發送到CA, CA將為密鑰生成證書(通常在確保CSR中的身份信息與服務器的真實身份匹配之後)。使用SEEDPKILab2018.com作為證書請求的通用名稱。

    需要注意的是,上面的命令與我們為CA創建自簽名證書時使用的命令非常相似,唯一的區別是使用了-x509選項。沒有它,命令生成一個請求;使用它,該命令生成一個自簽名證書。

    Step 3: Generating Certificates . CSR文件需要有CA的簽名才能形成證書。在現實世界中,CSR文件通常被發送到受信任的CA進行簽名。在這個實驗中,我們將使用我們自己的可信CA來生成證書。以下命令使用CA的CA .crt和CA .key將證書籤名請求(server.csr)轉換為X509證書(server.crt):

    如果OpenSSL拒絕生成證書,您請求中的名稱很可能與ca的名稱不匹配。匹配規則在配置文件中指定(查看[policy match]部分)。您可以更改請求的名稱以符合策略,也可以更改策略。配置文件還包括另一個限制較少的策略(稱為任何策略)。您可以通過更改以下行來選擇該策略:

    “policy = policy_match” change to “policy = policy_anything”.

    Task3: Deploying Certificate in an HTTPS Web Server

    在這個實驗中,我們將探索網站如何使用公鑰證書來保護web瀏覽。我們將使用openssl的內置web服務器建立一個HTTPS網站。

    Step1: Configuring DNS .我們選擇SEEDPKILab2018.com作為我們的網站名稱。為了讓我們的計算機識別這個名稱,讓我們將下面的條目添加到/etc/hosts;這個條目基本上將主機名SEEDPKILab2018.com映射到本地主機(即127.0.0.1):

     

    Step 2: Configuring the web server.  讓我們使用在上一個任務中生成的證書啟動一個簡單的web服務器。OpenSSL允許我們使用s_server命令啟動一個簡單的web服務器:

     

    默認情況下,服務器將監聽端口4433。您可以使用-accept選項進行更改。現在,您可以使用以下URL訪問服務器:https://SEEDPKILab2018.com:4433/。最有可能的是,您將從瀏覽器中得到一條錯誤消息。在Firefox中,您將看到如下消息:“seedpkilab2018.com:4433使用了無效的安全證書。該證書不受信任,因為發布者證書未知”.

     

    Step3: Getting the browser to accept our CA certificate. 如果我們的證書是由VeriSign分配的,就不會出現這樣的錯誤消息,因為VeriSign的證書很可能已經預加載到Firefox的證書存儲庫中了。很遺憾,SEEDPKILab2018.com的證書是由我們自己的CA,並且Firefox無法識別此CA。有兩種方法可以讓Firefox接受CA的自簽名證書。

    • 我們可以請求Mozilla將我們的CA證書包含在Firefox軟件中,這樣每個使用Firefox的人都可以識別我們的CA。不幸的是,我們自己的CA沒有足夠大的市場讓Mozilla包含我們的證書,所以我們不會追求這個方向。
    • 加載CA .crt到Firefox中:我們可以手動添加我們的CA證書到Firefox瀏覽器通過點擊下面的菜單序列:

                 Edit -> Preference -> Privacy & Security -> View Certificates

    您將看到一個已經被Firefox接受的證書列表。從這裏,我們可以“導入”我們自己的證書。請導入CA .crt,並選擇以下選項:“信任此CA識別網站”。您將看到我們的CA證書現在位於Firefox接受的證書列表中。

     Step4. Testing our HTTPS website . 現在,將瀏覽器指向https://SEEDPKILab2018.com: 4433,可以正常訪問

    Task4: Deploying Certificate in an Apache-Based HTTPS Website

    使用openssl的s_server命令設置HTTPS服務器主要用於調試和演示目的。在這個實驗中,我們基於Apache建立了一個真正的HTTPS web服務器。Apache服務器(已經安裝在我們的VM中)支持HTTPS協議。要創建一個HTTPS網站,我們只需要配置Apache服務器,這樣它就知道從哪裡獲得私鑰和證書。

    一個Apache服務器可以同時託管多個網站。它需要知道網站文件存儲的目錄。這是通過它的VirtualHost文件完成的,該文件位於/etc/apache2/sites-available目錄中。要添加一個HTTP網站,我們需要在文件000-default.conf中添加一個虛擬主機條目。而要添加一個HTTPS網站,我們則需要在同一個文件夾的default-ssl.conf文件中添加一個VirtualHost條目。

     

     

    ServerName條目指定網站的名稱,而DocumentRoot條目指定網站文件存儲的位置。在設置中,我們需要告訴Apache服務器證書和私鑰存儲在哪裡。

    修改了default-ssl.conf文件之後,我們需要運行一系列命令來啟用SSL。Apache將要求我們輸入用於加密私鑰的密碼。一旦一切都設置好了,我們就可以瀏覽網站了,瀏覽器和服務器之間的所有流量都被加密了。

     

     Task5: Launching a Man-In-The-Middle Attack 

     

     在這個任務中,我們將展示PKI如何擊敗中間人(MITM)攻擊。下圖描述了MITM攻擊的工作原理。假設Alice想通過HTTPS協議訪問example.com。她需要從example.com服務器獲取公鑰;Alice將生成一個密鑰,並使用服務器的公鑰對該密鑰進行加密,然後將其發送到服務器。如果攻擊者可以攔截Alice和服務器之間的通信,則攻擊者可以用自己的公鑰替換服務器的公鑰。因此,Alice的秘密實際上是用攻擊者的公鑰加密的,因此攻擊者將能夠讀取秘密。攻擊者可以使用服務器的公鑰將密鑰轉發給服務器。秘密用於加密Alice和服務器之間的通信,因此攻擊者可以解密加密的通信。

     

     

    Step 1: Setting up the malicious website. 在Task 4中,我們已經為SEEDPKILab2018.com建立了一個HTTPS網站。我們將使用相同的Apache服務器模擬example.com 。為此,我們將按照任務4中的指令向Apache的SSL配置文件添加一個VirtualHost條目:ServerName應該是example.com,但配置的其餘部分可以與任務4中使用的相同。我們的目標如下:當用戶試圖訪問example.com時,我們將讓用戶登陸我們的服務器,其中為example.com託管一個假網站。如果這是一個社交網站,虛假網站可以显示一個登錄頁面類似於目標網站。如果用戶不能分辨出兩者的區別,他們可能會在假網頁中輸入他們的帳戶憑據,本質上就是向攻擊者披露憑據。

    Step2: Becoming the man in the middle 。有幾種方法可以讓用戶的HTTPS請求到達我們的web服務器。一種方法是攻擊路由,將用戶的HTTPS請求路由到我們的web服務器。另一種方法是攻擊DNS,當受害者的機器試圖找到目標網絡服務器的IP地址時,它會得到我們的網絡服務器的IP地址。在此任務中,我們使用“攻擊”DNS。我們只需修改受害者機器的/etc/hosts文件,以模擬DNS緩存設置攻擊的結果,而不是啟動實際的DNS緩存中毒攻擊。

    Step3: Browse the target website  。一切都設置好了,現在訪問目標真實的網站。

    可以看到,我們訪問到的是kali攻擊機的默認目錄。

    訪問https服務的時候,由於kali攻擊機的證書不被信任,所以會有安全警告

     

     

     

    Task6: Launching a Man-In-The-Middle Attack with a Compromised CA 

    設計一個實驗來證明攻擊者可以在任何HTTPS網站上成功發起MITM攻擊。可以使用在Task 5中創建的相同設置,但是這一次,需要演示MITM攻擊是成功的。即,當受害者試圖訪問一個網站而進入MITM攻擊者的假網站時,瀏覽器不會引起任何懷疑。

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    ※教你寫出一流的銷售文案?

  • 搭載寶馬發動機!這車還沒上市就引起轟動!

    搭載寶馬發動機!這車還沒上市就引起轟動!

    不僅如此,華晨中華V7採用麥弗遜式獨立前懸、扭力梁式/多連桿式后懸,底盤系統由寶馬和麥格納參与優化,可輕鬆駕馭各種複雜地形和艱險路段,感受隨心而馭、征服天地的操控樂趣。共享寶馬供應商,帶來豪華車的品質體驗。

    4月25日,代表着華晨中華與德國寶馬十五年全產業鏈融合的里程碑之作——中級SUV華晨中華V7在北京車展耀世登場,全球首發。嚴格按照寶馬開發設計流程、搭載BMW授權生產的發動機,與寶馬共享核心供應商體系、按照德系標準生產,顛覆而生的華晨中華V7,旨在以純正德系豪華品質體驗為消費者帶來自主高端SUV新選擇,這也意味着華晨中華與寶馬走向深度融合的全新階段,華晨中華品牌自此邁向“中國寶馬”時代的新起點。

    十五載與巨人同行 華晨中華破繭化蝶

    2003年百年寶馬來到中國,憑藉雄厚的工業基礎和領先的技術優勢,華晨中華成為寶馬在華唯一的合作夥伴,從此開創了中外汽車工業合資合作的傳奇典範。

    攜手十五年,雙方互信共進,華晨中華在寶馬的支持下得到了長足的進步,從造車理念到核心技術、質量控制等,華晨中華始終以德系品質和技術為標準,完成了品質升級和技術沉澱。在品質方面,華晨中華全面引入寶馬品質標準,包括寶馬質量標準體系、寶馬“零缺陷”管理理念、寶馬VpS生產增值系統,在業內首創了產品經理制度和首席質量官制度,建立了貫穿產品質量全過程的ppQ1-10質量保障體系,從生產到研發華晨中華均以德系標準締造高品質自主精品。

    在核心技術方面,華晨中華獲得寶馬授權生產N20及王子系列四款符合歐六排放標準的世界先進發動機,華晨中華因此也成為中國改革開放三十多年來汽車行業唯一一個從合資夥伴取得當代先進核心技術的中方企業。

    掌握了汽車發動機核心技術的華晨中華再次乘勝追擊,在寶馬的支持下,聯合麥格納聯手打造全新M8X智能模塊化平台,該平台在德國工業4.0基礎上構建,並汲取寶馬面向未來的ACES造車戰略理念,具有全面引入寶馬開發流程、原生寶馬技術、寶馬智能製造、智能駕駛等領先優勢。是華晨中華與德國寶馬十五年攜手共進、融匯雙方合作精髓的集大成之作。具備擴展衍生系列化中高端戰略車型的能力。

    M8X智能模塊化平台的到來標志著華晨中華的發展啟動了強勁新引擎,華晨中華正處於品牌與技術厚積薄發的前夜,開創了自主品牌的新時代。

    打造“中國寶馬”華晨中華V7賦能品牌新未來

    作為M8X平台的首款產品,華晨中華V7具備最領先的技術基因、最先進的智能製造水準,最純正的寶馬血統和最高的安全標準,是中國自主品牌中真正具備豪門氣質的划時代傑作。華晨中華V7的推出,對於中華品牌而言不僅是自我的顛覆,更是從動力、品質、安全、智能化四大維度重新定義了自主高端SUV的產品力。

    搭載寶馬源動力,感受純正德系操控樂趣。全新華晨中華V7搭載BMW授權生產的發動機集雙渦管增壓、高精度直噴、連續可變氣門升程、雙連續可變氣門正時等技術於一身,在寶馬專家支持下優化動力總成系統方案設定、匹配,以及對發動機控制系統的重新調校,在格特拉克7速濕式雙離合變速箱的配合下,更將這款發動機的性能發揮到極致,動輸出高達150千瓦,峰值扭矩達280牛·米,百公里加速僅為8.9秒。不僅如此,華晨中華V7採用麥弗遜式獨立前懸、扭力梁式/多連桿式后懸,底盤系統由寶馬和麥格納參与優化,可輕鬆駕馭各種複雜地形和艱險路段,感受隨心而馭、征服天地的操控樂趣。

    共享寶馬供應商,帶來豪華車的品質體驗。隨着華晨中華與德國寶馬合作的深度融合,華晨中華V7所有核心部件共享了寶馬供應商體系:發動機來自BMW授權生產的發動機,變速箱來自格特拉克。此外,更有德國大陸、博世、曼胡默爾、貝爾,美國TRW、德爾福、天納克、江森,法國法雷奧、米其林、意大利馬瑞利,日本海德世、日本三電,韓國岱摩斯、萬都,奧地利MSE等全球零部件領域頂尖品牌組成豪華天團,置身其中,讓德系豪華車尊崇精緻的品質體驗油然而生。

    五星標準設計,暢享安全出行體驗。承襲百年寶馬對安全的執著追求,華晨中華V7按照2018版全新C-NCAp五星標準進行設計,提升對車內外人員全方位主被動保護能力。選用與BMW相同品質的寶鋼板材,高強度鋼比例達到56%,屬同級最高水平。熱成型加強鋼天窗骨架,安全穩定,A、B柱採用超高強熱成型鋼板,抗拉強度超過1500Mpa,事故中能有效減少駕駛艙變形,保護駕乘人員的安全。此外,華晨中華V7配置了同級中先進防碰撞預警+自動緊急剎車系統,以及領先同級的車道偏離預警系統、盲區監測,以陪伴之心呵護安全,讓每一段旅途都心安。

    萬物互聯,跨越時空的智能體驗。移動互聯時代,萬物盡在雲端,一切盡在掌控。華晨中華V7通過車載WIFI,駕乘者能0秒與世界互聯,配備同級別尺寸最大的10.4寸中控屏,搭載BriAir2.0車聯網系統,可實現語音控制、遠程控制、智聯娛樂等功能,為提供用戶極致人性化的智能汽車新體驗。用戶可通過手機App遠程了解車況,實現對發動機、空調、車窗、車鎖等全方位控制,尋車、防盜報警等智能化功能能夠實現即使人車分離也能對車輛狀況了如指掌。車輛與智能手機的“無縫接軌”,讓智能體驗跨越時空、時刻隨行。

    華晨中華V7的到來以德系標準開啟了華晨中華品牌進入“中國寶馬”時代,代表了追求極致性能自主高端SUV新勢力的崛起,為更多用戶帶來純正德系豪華SUV的新體驗。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化