前文演示了在單一容器中部署 Nginx和ASP.NET Core WebApp, 正在前文評論區某大牛指出的,容器化部署 nginx+ASP.NET Core 有更符合實戰的部署選擇:多容器獨立部署。html
此次記錄我在工做中利用 docker-compose部署企業級web應用。nginx
本文會講述企業級示例項目中用到的 docker volume、docker network、redis、sqlite、docker HealthCheck 等相關知識, 略去CentOS平臺基本操做、Linux 下安裝Docker ,docker compose工具, Linux安裝Redis等前置知識點。
Web App業務上依賴第三方服務、容器外Redis服務、Sqlite數據庫,能夠想見咱們會利用到 docker Volume機制和部分容器網絡知識,web
此處咱們會以獨立容器分別部署ASP.NETCore WebApp、Nginx容器,docker-compose 容器編排工具登場。redis
利用dotnet publish CLI命令或者 WebDeploy工具生成部署文件,將部署文件拷貝到以下圖示publish文件夾sql
EqidManager ├── app │ ├── Dockerfile │ └── publish ├── applogs ├── docker-compose.yml ├── EqidManager.db └── nginx ├── Dockerfile └── nginx.conf
Docker 的優點很是明顯,尤爲是對於開發者來講,它提供了一種全新的軟件發佈機制:使用 docker鏡像做爲軟件產品的載體,使用 docker容器提供獨立的軟件運行上下文環境,使用 docker hub 等提供鏡像的集中管理,這其中最重要的是使用 Dockerfile 定義容器的內部行爲和關鍵屬性來支持軟件運行。docker
但實際的生產環境每每須要定義數量龐大的 docker 容器,而且容器之間具備錯綜複雜的聯繫,手動的記錄和配置這些複雜的容器關係,不只效率低下並且容易出錯。因此迫切須要一種相似於【Dockerfile定義docker容器】那樣可以【定義容器集羣編排和部署】的工具。因而Docker Compose 出現了(其實應該說 Fig 出現了,docker 收購了 Fig 並更名爲 compose)。數據庫
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
logging:
options:
max-size: "200k"
max-file: "10" proxy: build: context: ./nginx dockerfile: Dockerfile ports: - "80:80" environment: TZ: Asia/Shanghai
links:
- app
logging:
options:
max-size: "200k"
max-file: "10"
這個配置定義了兩個服務: app、nginx網絡
對於每一個服務,【build】 告訴Docker Compose怎樣爲每一個服務構建鏡像架構
【expose】和【ports】控制服務與 network bridge、宿主機交互的方式app
【links】代表連接另外的容器,意味着nginx啓動的時會去啓動app服務
在本應用程序中有業務數據須要被持久化, 同時使用了Sqlite數據庫,因此使用 【Volumes】來映射宿主機路徑到 app 容器內路徑
本應用程序中由於涉及按小時生成業務日誌文件,與本地時間有很大關聯性,這裏特地強調容器內外最好使用同一時區, 容器內默認時區可能與宿主機本地不符,使用【TZ】環境變量配置容器內時區
應用程序在http://localhost/healthcheck 配置了健康檢查能力, 這裏使用Docker內置的【HealthCheck】指令輪詢 app內的健康檢查端口, 以判斷容器是否持續以預期的方式運做, 更多信息,請參考...
其中的【extra_hosts】在容器內添加主機名映射, 類比與 在咱們的電腦上hosts文件中增長一行主機名映射關係, 這個稍後會細說
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 WORKDIR /app COPY publish . EXPOSE 80 ENTRYPOINT ["dotnet","EqidManager.dll"]
上面的Dockerfile 顯示將publish 文件件下的部署文件拷貝進docker鏡像, 配置容器在80端口監聽請求
FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf
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 文件中指定的服務名稱。
在CentOS上安裝了docker-compose工具以後, docker-compose --help 會看到能夠利用的工具指令:
// build 命令會構建/重建每個服務, 而後使用項目名稱和服務名稱標記每一個鏡像、容器
docker-compose build
// up 命令建立並運行容器
docker-compose up
以下圖示: docker-compose 默認會利用項目名稱EqidManager , 應用程序服務名稱app 構建 ImageName=「EqidManager_app」鏡像和對應容器。
本例中,訪問localhost:80可驗證是否成功部署。
最後咱們來探究容器集合的網絡鏈接, 這也是容器比較複雜的部分。
當執行docker-compose時,會建立一個共享網橋設備,集合內全部服務均可經過該網橋交流。
建立名稱是 {project}_default 的網橋
使用【app】配置建立容器,同時將名爲app的服務加入 {project}_default 網絡
使用【nginx】配置建立容器,同時將名爲nginx的服務加入 {project}_default 網絡
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" } } ]
本實例中宿主機在這個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是個好東西,越用越香,
但願本文對初涉容器平臺的同窗能有一個拋磚引玉的效果。
感謝您的認真閱讀,若有問題請大膽斧正;以爲有用,請下方或加關注。
本文歡迎轉載,但請保留此段聲明,且在文章頁面明顯位置註明本文的做者及原文連接。