最近花了將近一個月的時間研究了 Docker 在生產環境中的使用,做爲新手,期間走了無數的彎路,這裏紀錄一下,但願給別人帶來微小的幫助。php
前面幾部分,介紹了在搭建集羣以前須要作的一些工做,後面 <集羣實踐> 一塊結合實際應用,介紹如何架構 docker 集羣。html
生產環境中,鏡像多了以後很容易把硬盤寫滿形成服務器宕機,因此須要掛載一塊較大的硬盤,修改 docker 的默認存儲路徑,下面提供兩種方案。node
方案一:軟鏈接nginx
service docker stop mv /var/lib/docker /mnt/sdc/docker ln -s /mnt/sdc/docker /var/lib/docker
方案二:修改配置git
配置 deamon 啓動時 -g
參數,能夠直接改變存儲路徑。github
Ubuntu 系統須要先修改 /lib/systemd/system/docker.service
文件:web
... [Service] ExecStart=/usr/bin/docker -d $DOCKER_OPTS ... EnvironmentFile=-/etc/default/docker ...
其中 ExecStart
就是 deamon 的啓動命令,能夠直接在後面加參數,也能夠選擇上述 EnvironmentFile
配置 ,而後將啓動參數寫到 /etc/default/docker
文件中:docker
DOCKER_OPTS="-g /mnt/sdc/docker"
配置好以後,執行下面命令從新加載配置文件:ubuntu
systemctl daemon-reload systemctl restart docker
參考:How do I change the Docker image installation directory?segmentfault
生產環境中部署 docker,須要在搭建一個私有 registry:
docker run -d -p 5000:5000 --restart=always --name registry registry:2
啓動以後,無法直接進行鏡像的 push/pull,由於默認要求配置 TLS。
爲了圖方便,能夠暫時把私有的 registry 加入爲 insecure-registry
進行測試。
insecure-registry
也是經過添加 deamon 的啓動參數實現的,可在 /etc/default/docker
中配置:
DOCKER_OPTS="--insecure-registry 192.168.1.19:5000"
而後重啓便可。
參考:Deploying a plain HTTP registry
docker 集羣部署目前有兩種方案,通常稱做 一代 swarm
和 二代 swarm
。
官方文檔。
一代 swarm 是以容器的方式進行集羣管理的,須要在每一個節點上運行一個 swarm 容器,即可進行集羣管理,簡單部署測試可參考: 在ubuntu上使用swarm搭建docker集羣。
須要注意的是,一代 swarm 還須要本身手動運行 k/v 服務容器,參考,運行起來以後可能會遇到報錯:
Error response from daemon: datastore for scope "global" is not initialized
這實際上是 deamon 沒有配置 cluster-advertise
和 cluster-store
所致,須要在/etc/default/docker
中配置這兩項,具體可參考 Nodes discovery。
官方文檔。
二代 swarm 直接將 swarm 模式集成在 docker 裏面,只須要簡單的配置便可,參考:Create a swarm。
在以前的文章中,介紹過 ui-for-docker 做爲管理的 web 界面,可是過於簡陋,後來有找到一個基於 ui-for-docker 實現的 portainer,支持 swarm mode,使用起來很是方便,也能夠根據本身的需求修改。
實踐過程當中我分別嘗試了一代 swarm 和二代 swarm。
版本 | 配置過程 | 管理 | 擴容 |
---|---|---|---|
一代 | 1. 配置 k/v store。2. 宿主機 docker deamon 監聽某個端口。 3.在每臺宿主機上運行 swarm 容器。 | 在任何一個節點均可以進行集羣的管理 | 手動擴容 |
二代 | 1. manager init swarm mode 2. worker join | 只能在 manager 節點進行管理 | 自動擴容 |
目前實現了把 Segmentfault 的 web 服務遷移到容器中,簡單的說就是一個 nginx + php 的環境,如下是具體步驟:
使用二代 swarm。
建立一個 overlay 網絡。
建立 nginx 服務。
建立 php 及 web 代碼服務。
須要明確的幾點:
二代 swarm 在同一個網絡下服務能夠經過服務名發現其餘服務。
二代 swarm 部署以後,將會監聽每一個節點上 publish 的端口,收到的請求會負載均衡到全部的 tasks 中。
nginx 服務只需選擇官方提供的鏡像,建議使用最輕量的 nginx:alpine
版本,自定義配置文件覆蓋原生的便可。
鏡像直接基於官方發佈的php版本版本建立。
注意: ubuntu 宿主機儘可能使用 Debian
版本的基礎鏡像,其餘的可能會遇到各類坑。
我在開始爲了追求鏡像儘可能小,使用了基於 alpine
的基礎鏡像,遇到了如下問題:
7.1.0RC5-fpm-alpine
版本,使用 session_set_save_handler 修改 session 的 save header 爲 memached 以後無法寫入 session,換成了 7.0.12-alpine
就行了。
web 代碼對 mount 到容器中的 www-data
用戶所屬的目錄沒有寫入權限,是由於 alpine
系統中默認 www-data
的 uid
是 82, 而宿主機 Ubuntu/Debian
的是 33,在 alpine
中 uid
是 33 的用戶是 xfs
,因此 mount 以後容器內部看到的文件所屬用戶是 xfs
,而 php-fpm 的執行用戶是 www-data
, 因此纔沒法寫入。
解決辦法就是棄用 alpine
,使用基於 Debian
的基礎鏡像,這樣帶來的代價就是鏡像大小翻了 10 倍。
RUN apk update && apk add ca-certificates && \ apk add tzdata && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ echo "Asia/Shanghai" > /etc/timezone
還有 php.ini 的時區配置。
docker 容器的 /etc/hosts
文件默認是不容許修改的,因此要自定義域名的解析就須要配置本身的內網 DNS 服務,推薦使用 dnsmsq
, 而後將 deamon 的啓動參數修改成 --dns=192.168.x.x
本身的 DNS 服務器,就能夠實現自定義域名解析的需求。
上述修改可解決服務器被牆致使谷歌、Facebook 等三方API沒法使用的問題,也能夠加速服務器訪問外網。
做爲 web 應用,代碼須要時常上線更新,又須要在集羣中部署,若是使用目錄掛載的辦法將帶來額外的工做量,因此選擇把代碼直接打包到 php 容器中,每次上線從新構建鏡像,具體步驟:
代碼 push 到 gitlab,觸發 CI 或者 webhook,構建鏡像。
鏡像 push 到私有的 registry 倉庫中。
二代 swarm 提供 rolling update 的機制,執行相關命令便可。
Docker 是進程容器,理論上一個容器只跑一個進程,杜絕當虛擬機使用。
要使用和宿主機一個體系的基礎鏡像。
國內使用建議搜索下 daocloud 鏡像加速,會提高幸福感。
DNS 服務器會默認使用 8.8.8.8
,因此正式環境必定要配置 DNS 服務器,不然一些三方登陸的接口將會變得異常緩慢。
Docker 裏面包含了不少新的思路,若是老是用老套路去思考,極可能就走入死衚衕。
不要用百度搜索中文資料,必定要看最新的英文資料。
爲了安全,確保 deamon 只監聽 /var/run/docker.sock
。
感謝能容忍我無數次搞掛生產環境的老闆。
感謝每次走入死衚衕後一句話點醒個人同事。
感謝羣裏每一位幫助個人朋友。
感謝本身的堅持。