1. 程式人生 > >docker-compose 是個好東西,越用越香

docker-compose 是個好東西,越用越香

 回顧前文

        前文演示了在單一容器中部署 Nginx和ASP.NET Core WebApp, 正在前文留言中某位大牛指出的,容器化部署 nginx+ASP.NETcore 有更生產化的部署選擇,

        這次我們會演示利用 docker-compose 建立兩個獨立的容器 部署企業級應用。

   本文會講述企業級示例專案中用到的 docker volume、docker network、redis、sqlite、docker HealthCheck 等相關知識, 略去CentOS平臺基本操作、Linux 下安裝Docker, Linux安裝Redis等前置知識點。
 

頭腦風暴

  圖片總是比文字更能表達思想,下面圖示幫助同學們在頭腦中快速臨摹出本次企業級專案的業務、部署流程, 方便同學們對照實戰。

WebApp業務上依賴第三方服務、容器外Redis服務、Sqlite資料庫,可以想見我們會利用到 docker Volume機制和部分容器網路知識,

此處我們會以獨立容器分別部署ASP.NETCore WebApp、Nginx容器,docker-compose 容器編排工具登場。

 

操作步驟

 

1. 準備應用程式部署檔案

       利用dotnet publish CLI命令或者 WebDeploy工具生成部署檔案,將部署檔案拷貝到如下圖示publish資料夾

.
├── app
│   ├── Dockerfile
│   └── publish
├── applogs
├── docker-compose.yml
├── EqidManager.db
└── nginx
    ├── Dockerfile
   └── nginx.conf

 

2. 應用docker-compose 工具

         這次Docker設定將涉及兩個獨立的Docker容器,Docker Compose配置將兩者連線在一起。
Docker Compose用於執行多容器Docker應用程式,通過docker-compose.yml檔案,您可以配置多個應用程式容器,然後,您可以構建並執行容器集合(類似於單個容器的方式)。
         針對以上應用程式,在根目錄下建立docker-compose.yml 檔案:
version: "3.4"

services:
  app:
    build:
      context: ./app
      dockerfile: Dockerfile
    expose:
      - "80"
    extra_hosts:
      - "dockerhost:172.18.0.1"
    environment:
      TZ: Asia/Shanghai 
    volumes:
      - type: bind
        source: /mnt/eqidmanager/eqidlogs
        target: /app/eqidlogs
      - type: bind
        source: /home/huangjun/eqidmanager/applogs
        target: /app/logs
      - type: bind
        source: /home/huangjun/eqidmanager/EqidManager.db
        target: /app/EqidManager.db
    healthcheck:
      test: ['CMD','curl','-f','http://localhost/healthcheck']
      interval: 1m30s
      timeout: 10s
      retries: 3
      start_period: 6s
  proxy:
    build:
      context: ./nginx
      dockerfile: Dockerfile
    ports:
      - "80:80"
    environment:
      TZ: Asia/Shanghai
    links:
      - app

 

這個配置定義了兩個服務: app、nginx

  •  對於每個服務,【build】 告訴Docker Compose怎麼去為每個服務構建映象

  • 【expose】和【ports】控制服務與 network bridge、宿主機互動的方式

  • 【links】表明連結另外的容器,意味著 代理服務啟動的時候撿回去啟動app服務

  •  在本應用程式中有業務資料需要被持久化, 同時使用了Sqlite資料庫,所以使用 【Volumes】來對映宿主機路徑到 app 服務

  • 本應用程式中因為涉及按小時生成業務日誌檔案,與本地時間有很大關聯性,這裡特意強調容器內外最好使用同一時區, 容器內預設時區可能與宿主機本地不符,使用【TZ】環境變數配置容器內時區

  • 應用程式在http://localhost/healthcheck 配置了健康檢查能力, 這裡使用Docker內建的【HealthCheck】指令輪詢 app內的健康檢查埠, 以判斷容器是否持續以預期的方式運作, 更多資訊,請參考...

  • 其中的【extra_hosts】在容器內新增主機名對映, 類比與 在我們的電腦上hosts檔案中增加一行主機名對映關係, 這個稍後會細說

 

3. 建立獨立映象

    ① 在app目錄建立Dockerfile檔案

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY publish .
EXPOSE 80
ENTRYPOINT ["dotnet","EqidManager.dll"]
View Code

      上面的Dockerfile 顯示將publish 檔案件下的部署檔案拷貝進docker映象, 配置容器在80埠監聽請求 

   ② 在nginx資料夾下建立Dockerfile 檔案,將會使用基礎nginx映象和自定義的nginx.conf檔案

 FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
View Code

      nginx.conf 檔案與前文類似:

worker_processes 4;
 
events { worker_connections 1024; }
 
http {
    sendfile on;
 
    upstream app_servers {
        server app:80;
    }
 
    server {
        listen 80;
 
        location / {
            proxy_pass         http://app_servers;
            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
        }
    }
}

     該nginx.conf與前文的區別是第9 行,前文因為app和nginx在一個容器,所以【upstream app_servers】配置為 server  localhost:5000, 這裡我們更改為server  app:80, 其中app是在docker-compose.yml 檔案中指定的服務名稱。

 

4. 構建容器集合 --> 執行集合

在CentOS上安裝了docker-compose工具之後, docker-compose --help 會看到可以利用的工具指令:

// build 命令會構建/重建每一個服務, 然後使用專案名稱和服務名稱標記每個映象、容器

docker-compose build

// up 命令建立並執行容器

docker-compose up

如下圖示: docker-compose 預設會利用專案名稱EqidManager , 應用程式服務名稱app 構建 ImageName=“EqidManager_app”映象和對應名稱容器。

本例中,訪問localhost:80可驗證是否成功部署。

--------------------------------------------------------------------------華麗麗的分割線  ------------------------------------------------------------------------

Network

      最後我們來探究容器集合的網路連線, 這也是容器比較複雜的部分。

  當執行docker-compose時,會建立一個共享網橋裝置,集合內所有服務都可通過該網橋交流。

  • 建立名稱是 {project}_default 的網橋

  • 使用【app】配置建立容器,同時使用服務名稱app 加入 {project}_default 網路

  • 使用【nginx】配置建立容器,同時使用服務名稱nginx 加入 {project}_default 網路

     每一個容器現在可使用 “app”/“nginx” 主機名,這些主機名可得到正確的容器IP, 所以在nginx.conf 檔案中我們給 【upstream app_servers】配置 app:80 能正確轉發請求:  

  docker-compose.yml檔案中【extra_hosts】的用法:

     當前程式架構中使用的Redis 服務是宿主機的常駐服務,在app 容器內不能再使用localhost:6379引用redis服務, 因為容器內localhost 指向的是容器自身。

     【extra_hosts】指令用於主機名對映,該主機名代表了宿主機的機器IP,可通過docker inspect [network_id] 檢視宿主機在網橋上的對映IP:

[root@search-referer1 nginx]# docker inspect 0b576abb7ead
[
    {
        "Name": "eqidmanager_default",
        "Id": "0b576abb7ead9041a4aa0fe786c3e448f0ca93abe2559560e75f491bea326754",
        "Created": "2019-04-30T00:53:31.047534813+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "Containers": {
            "f0b08e0e54e7e9293211bba0eb92f55749c3de4b31dc8011c3f803c02a69000a": {
                "Name": "eqidmanager_proxy_1",
                "EndpointID": "1311f2b21b2a0ecec205e6a8902d298eece8a782f7f7ab785ded6561b8ff7c5e",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "f57f5f1f69351245932885c2de271d387df0055b1c51a17242c8bc1e941ed32b": {
                "Name": "eqidmanager_app_1",
                "EndpointID": "b89d144948ee58870e07b9d1cfc5fd42f1bfe0a4b15e4fc2905d13136acb0a7e",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "eqidmanager",
            "com.docker.compose.version": "1.24.0"
        }
    }
]
View Code

      本例項中宿主機在這個eqidmanager_default 網橋上的閘道器是 172.18.0.1,所以在docker-compose.yml 檔案中配置了上述【extra_hosts】,在對應的app容器內我們cat  /etc/hosts 會發現新增的對映記錄:

 

 相應的我們連線字串是 :

"connectionstrings": {
    ”sqlite": "Data Source=EqidManager.db",
     "redis": "dockerhost:6379,password=****@1,connectTimeout=10000,writeBuffer=40960"
},

 

 That‘s all, 編寫一個企業級docker-compose.yml 檔案需要對專案業務流程和部署流程有全盤瞭解,同時必須要具備完備的計算機操作原理和網路原理知識;

     當然,當你編寫完一個企業級docker-compose.yml檔案併成功執行,這也印證了你已經全盤熟悉專案架構同時也重溫了計算機操作原理和網路原理,

      心中竊喜, docker-compose是個好東西,越用越香,

      希望本文對初涉容器平臺的同學能有一個拋磚引玉的效果。

作者:Julian_醬

感謝您的認真閱讀,如有問題請大膽斧正,如果您覺得本文對你有用,碼甲何必為難碼甲,不妨幫忙點個或加關注,蟹蟹      ~。。~

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置註明本文的作者及原文連結,否則保留追究法律責任的權利。