這次專治Docker疑難雜癥
點(diǎn)擊上方 Java學(xué)習(xí)之道,選擇 設(shè)為星標(biāo)
來源: escapelife.github.io/posts/43a2bb9b.html
作者: Escape
這里主要是為了記錄在使用 Docker 的時(shí)候遇到的問題及其處理解決方法。
Part1Docker 遷移存儲(chǔ)目錄
默認(rèn)情況系統(tǒng)會(huì)將 Docker 容器存放在/var/lib/docker 目錄下
-
[問題起因] 今天通過監(jiān)控系統(tǒng),發(fā)現(xiàn)公司其中一臺(tái)服務(wù)器的磁盤快慢,隨即上去看了下,發(fā)現(xiàn) /var/lib/docker這個(gè)目錄特別大。由上述原因,我們都知道,在/var/lib/docker中存儲(chǔ)的都是相關(guān)于容器的存儲(chǔ),所以也不能隨便的將其刪除掉。 -
那就準(zhǔn)備遷移 docker的存儲(chǔ)目錄吧,或者對(duì)/var設(shè)備進(jìn)行擴(kuò)容來達(dá)到相同的目的。更多關(guān)于dockerd的詳細(xì)參數(shù),請(qǐng)點(diǎn)擊查看 官方文檔 地址。 -
但是需要注意的一點(diǎn)就是,盡量不要用軟鏈, 因?yàn)橐恍? docker容器編排系統(tǒng)不支持這樣做,比如我們所熟知的k8s就在內(nèi)。
# 發(fā)現(xiàn)容器啟動(dòng)不了了
ERROR:cannot create temporary directory!
# 查看系統(tǒng)存儲(chǔ)情況
$ du -h --max-depth=1
-
[解決方法 1] 添加軟鏈接
# 1.停止docker服務(wù)
$ sudo systemctl stop docker
# 2.開始遷移目錄
$ sudo mv /var/lib/docker /data/
# 3.添加軟鏈接
$ sudo ln -s /data/docker /var/lib/docker
# 4.啟動(dòng)docker服務(wù)
$ sudo systemctl start docker
-
[解決方法 2] 改動(dòng) docker 配置文件
# 3.改動(dòng)docker啟動(dòng)配置文件
$ sudo vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --graph=/data/docker/
# 3.改動(dòng)docker啟動(dòng)配置文件
$ sudo vim /etc/docker/daemon.json
{
"live-restore": true,
"graph": [ "/data/docker/" ]
}
-
[操作注意事項(xiàng)] 在遷移 docker目錄的時(shí)候注意使用的命令,要么使用mv命令直接移動(dòng),要么使用cp命令復(fù)制文件,但是需要注意同時(shí)復(fù)制文件權(quán)限和對(duì)應(yīng)屬性,不然在使用的時(shí)候可能會(huì)存在權(quán)限問題。如果容器中,也是使用root用戶,則不會(huì)存在該問題,但是也是需要按照正確的操作來遷移目錄。
# 使用mv命令
$ sudo mv /var/lib/docker /data/docker
# 使用cp命令
$ sudo cp -arv /data/docker /data2/docker
-
下圖中,就是因?yàn)閱?dòng)的容器使用的是普通用戶運(yùn)行進(jìn)程的,且在運(yùn)行當(dāng)中需要使用 /tmp目錄,結(jié)果提示沒有權(quán)限。在我們導(dǎo)入容器鏡像的時(shí)候,其實(shí)是會(huì)將容器啟動(dòng)時(shí)需要的各個(gè)目錄的權(quán)限和屬性都賦予了。如果我們直接是cp命令單純復(fù)制文件內(nèi)容的話,就會(huì)出現(xiàn)屬性不一致的情況,同時(shí)還會(huì)有一定的安全問題。

Part2Docker 設(shè)備空間不足
Increase Docker container size from default 10GB on rhel7.
-
[問題起因一] 容器在導(dǎo)入或者啟動(dòng)的時(shí)候,如果提示磁盤空間不足的,那么多半是真的因?yàn)槲锢泶疟P空間真的有問題導(dǎo)致的。如下所示,我們可以看到 /分區(qū)確實(shí)滿了。
# 查看物理磁盤空間
$ df -Th
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 40G 0G 100% /
tmpfs 7.8G 0 7.8G 0% /dev/shm
/dev/vdb1 493G 289G 179G 62% /mnt
-
如果發(fā)現(xiàn)真的是物理磁盤空間滿了的話,就需要查看到底是什么占據(jù)了如此大的空間,導(dǎo)致因?yàn)槿萜鳑]有空間無法啟動(dòng)。其中, docker自帶的命令就是一個(gè)很好的能夠幫助我們發(fā)現(xiàn)問題的工具。
# 查看基本信息
# 硬件驅(qū)動(dòng)使用的是devicemapper,空間池為docker-252
# 磁盤可用容量僅剩16.78MB,可用供我們使用
$ docker info
Containers: 1
Images: 28
Storage Driver: devicemapper
Pool Name: docker-252:1-787932-pool
Pool Blocksize: 65.54 kB
Backing Filesystem: extfs
Data file: /dev/loop0
Metadata file: /dev/loop1
Data Space Used: 1.225 GB
Data Space Total: 107.4 GB
Data Space Available: 16.78 MB
Metadata Space Used: 2.073 MB
Metadata Space Total: 2.147 GB
-
**[解決方法]**通過查看信息,我們知道正是因?yàn)? docker可用的磁盤空間不足,所以導(dǎo)致啟動(dòng)的時(shí)候沒有足夠的空間進(jìn)行加載啟動(dòng)鏡像。解決的方法也很簡單,第一就是清理無效數(shù)據(jù)文件釋放磁盤空間(清除日志),第二就是修改docker數(shù)據(jù)的存放路徑(大分區(qū))。
# 顯示哪些容器目錄具有最大的日志文件
$ du -d1 -h /var/lib/docker/containers | sort -h
# 清除您選擇的容器日志文件的內(nèi)容
$ cat /dev/null > /var/lib/docker/containers/container_id/container_log_name
-
[問題起因二] 顯然我遇到的不是上一種情況,而是在啟動(dòng)容器的時(shí)候,容器啟動(dòng)之后不久就顯示是 unhealthy的狀態(tài),通過如下日志發(fā)現(xiàn),原來是復(fù)制配置文件啟動(dòng)的時(shí)候,提示磁盤空間不足。 -
后面發(fā)現(xiàn)是因?yàn)? CentOS7的系統(tǒng)使用的docker容器默認(rèn)的創(chuàng)建大小就是10G而已,然而我們使用的容器卻超過了這個(gè)限制,導(dǎo)致無法啟動(dòng)時(shí)提示空間不足。
2019-08-16 11:11:15,816 INFO spawned: 'app-demo' with pid 835
2019-08-16 11:11:16,268 INFO exited: app (exit status 1; not expected)
2019-08-16 11:11:17,270 INFO gave up: app entered FATAL state, too many start retries too quickly
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
-
[解決方法 1] 改動(dòng) docker 啟動(dòng)配置文件
# /etc/docker/daemon.json
{
"live-restore": true,
"storage-opt": [ "dm.basesize=20G" ]
}
-
[解決方法 2] 改動(dòng) systemctl 的 docker 啟動(dòng)文件
# 1.stop the docker service
$ sudo systemctl stop docker
# 2.rm exised container
$ sudo rm -rf /var/lib/docker
# 2.edit your docker service file
$ sudo vim /usr/lib/systemd/system/docker.service
# 3.find the execution line
ExecStart=/usr/bin/dockerd
and change it to:
ExecStart=/usr/bin/dockerd --storage-opt dm.basesize=20G
# 4.start docker service again
$ sudo systemctl start docker
# 5.reload daemon
$ sudo systemctl daemon-reload
-
[問題起因三] 還有一種情況也會(huì)讓容器無法啟動(dòng),并提示磁盤空間不足,但是使用命令查看發(fā)現(xiàn)并不是因?yàn)槲锢泶疟P真的不足導(dǎo)致的。而是,因?yàn)閷?duì)于分區(qū)的 inode節(jié)點(diǎn)數(shù)滿了導(dǎo)致的。
# 報(bào)錯(cuò)信息
No space left on device
-
[解決方法] 因?yàn)? ext3文件系統(tǒng)使用inode table存儲(chǔ)inode信息,而xfs文件系統(tǒng)使用B+ tree來進(jìn)行存儲(chǔ)。考慮到性能問題,默認(rèn)情況下這個(gè)B+ tree只會(huì)使用前1TB空間,當(dāng)這1TB空間被寫滿后,就會(huì)導(dǎo)致無法寫入inode信息,報(bào)磁盤空間不足的錯(cuò)誤。我們可以在mount時(shí),指定inode64即可將這個(gè)B+ tree使用的空間擴(kuò)展到整個(gè)文件系統(tǒng)。
# 查看系統(tǒng)的inode節(jié)點(diǎn)使用情況
$ sudo df -i
# 嘗試重新掛載
$ sudo mount -o remount -o noatime,nodiratime,inode64,nobarrier /dev/vda1
-
[補(bǔ)充知識(shí)] 文件儲(chǔ)存在硬盤上,硬盤的最小存儲(chǔ)單位叫做**“扇區(qū)”( Sector)。每個(gè)扇區(qū)儲(chǔ)存512字節(jié)(相當(dāng)于0.5KB)。操作系統(tǒng)讀取硬盤的時(shí)候,不會(huì)一個(gè)個(gè)扇區(qū)地讀取,這樣效率太低,而是一次性連續(xù)讀取多個(gè)扇區(qū),即一次性讀取一個(gè)“塊”(block)。這種由多個(gè)扇區(qū)組成的”塊”,是文件存取的最小單位?!眽K”的大小,最常見的是4KB,即連續(xù)八個(gè)sector組成一個(gè)block塊。文件數(shù)據(jù)都儲(chǔ)存在”塊”中,那么很顯然,我們還必須找到一個(gè)地方儲(chǔ)存文件的元信息,比如文件的創(chuàng)建者、文件的創(chuàng)建日期、文件的大小等等。這種儲(chǔ)存文件元信息的區(qū)域就叫做“索引節(jié)點(diǎn)”(inode)**。每一個(gè)文件都有對(duì)應(yīng)的inode,里面包含了除了文件名以外的所有文件信息。 -
inode也會(huì)消耗硬盤空間,所以硬盤格式化的時(shí)候,操作系統(tǒng)自動(dòng)將硬盤分成兩個(gè)區(qū)域。一個(gè)是數(shù)據(jù)區(qū),存放文件數(shù)據(jù);另一個(gè)是inode區(qū)(inode table),存放inode所包含的信息。每個(gè)inode節(jié)點(diǎn)的大小,一般是128字節(jié)或256字節(jié)。inode節(jié)點(diǎn)的總數(shù),在格式化時(shí)就給定,一般是每1KB或每2KB就設(shè)置一個(gè)inode節(jié)點(diǎn)。
# 每個(gè)節(jié)點(diǎn)信息的內(nèi)容
$ stat check_port_live.sh
File: check_port_live.sh
Size: 225 Blocks: 8 IO Block: 4096 regular file
Device: 822h/2082d Inode: 99621663 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 1006/ escape) Gid: ( 1006/ escape)
Access: 2019-07-29 14:59:59.498076903 +0800
Modify: 2019-07-29 14:59:59.498076903 +0800
Change: 2019-07-29 23:20:27.834866649 +0800
Birth: -
# 磁盤的inode使用情況
$ df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
udev 16478355 801 16477554 1% /dev
tmpfs 16487639 2521 16485118 1% /run
/dev/sdc2 244162560 4788436 239374124 2% /
tmpfs 16487639 5 16487634 1% /dev/shm
Part3Docker 缺共享鏈接庫
Docker 命令需要對(duì)/tmp 目錄下面有訪問權(quán)限
-
[問題起因] 給系統(tǒng)安裝完 compose之后,查看版本的時(shí)候,提示缺少一個(gè)名為libz.so.1的共享鏈接庫。第一反應(yīng)就是,是不是系統(tǒng)少安裝那個(gè)軟件包導(dǎo)致的。隨即,搜索了一下,將相關(guān)的依賴包都給安裝了,卻還是提示同樣的問題。
# 提示錯(cuò)誤信息
$ docker-compose --version
error while loading shared libraries: libz.so.1: failed to map segment from shared object: Operation not permitted
-
[解決方法] 后來發(fā)現(xiàn),是因?yàn)橄到y(tǒng)中 docker沒有對(duì)/tmp目錄的訪問權(quán)限導(dǎo)致,需要重新將其掛載一次,就可以解決了。
# 重新掛載
$ sudo mount /tmp -o remount,exec
Part4Docker 容器文件損壞
對(duì) dockerd 的配置有可能會(huì)影響到系統(tǒng)穩(wěn)定
-
[問題起因] 容器文件損壞,經(jīng)常會(huì)導(dǎo)致容器無法操作。正常的 docker命令已經(jīng)無法操控這臺(tái)容器了,無法關(guān)閉、重啟、刪除。正巧,前天就需要這個(gè)的問題,主要的原因是因?yàn)橹匦聦?duì)docker的默認(rèn)容器進(jìn)行了重新的分配限制導(dǎo)致的。
# 操作容器遇到類似的錯(cuò)誤
b'devicemapper: Error running deviceCreate (CreateSnapDeviceRaw) dm_task_run failed'
-
[解決方法] 可以通過以下操作將容器刪除/重建。
# 1.關(guān)閉docker
$ sudo systemctl stop docker
# 2.刪除容器文件
$ sudo rm -rf /var/lib/docker/containers
# 3.重新整理容器元數(shù)據(jù)
$ sudo thin_check /var/lib/docker/devicemapper/devicemapper/metadata
$ sudo thin_check --clear-needs-check-flag /var/lib/docker/devicemapper/devicemapper/metadata
# 4.重啟docker
$ sudo systemctl start docker
Part5Docker 容器優(yōu)雅重啟
不停止服務(wù)器上面運(yùn)行的容器,重啟 dockerd 服務(wù)是多么好的一件事
-
[問題起因] 默認(rèn)情況下,當(dāng) Docker守護(hù)程序終止時(shí),它會(huì)關(guān)閉正在運(yùn)行的容器。從Docker-ce 1.12開始,可以在配置文件中添加live-restore參數(shù),以便在守護(hù)程序變得不可用時(shí)容器保持運(yùn)行。需要注意的是Windows平臺(tái)暫時(shí)還是不支持該參數(shù)的配置。
# Keep containers alive during daemon downtime
$ sudo vim /etc/docker/daemon.yaml
{
"live-restore": true
}
# 在守護(hù)進(jìn)程停機(jī)期間保持容器存活
$ sudo dockerd --live-restore
# 只能使用reload重載
# 相當(dāng)于發(fā)送SIGHUP信號(hào)量給dockerd守護(hù)進(jìn)程
$ sudo systemctl reload docker
# 但是對(duì)應(yīng)網(wǎng)絡(luò)的設(shè)置需要restart才能生效
$ sudo systemctl restart docker
-
[解決方法] 可以通過以下操作將容器刪除/重建。
# /etc/docker/daemon.yaml
{
"registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"], # 配置獲取官方鏡像的倉庫地址
"experimental": true, # 啟用實(shí)驗(yàn)功能
"default-runtime": "nvidia", # 容器的默認(rèn)OCI運(yùn)行時(shí)(默認(rèn)為runc)
"live-restore": true, # 重啟dockerd服務(wù)的時(shí)候容易不終止
"runtimes": { # 配置容器運(yùn)行時(shí)
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-address-pools": [ # 配置容器使用的子網(wǎng)地址池
{
"scope": "local",
"base":"172.17.0.0/12",
"size":24
}
]
}
Part6Docker 容器無法刪除
找不到對(duì)應(yīng)容器進(jìn)程是最嚇人的
-
[問題起因] 今天遇到 docker容器無法停止/終止/刪除,以為這個(gè)容器可能又出現(xiàn)了dockerd守護(hù)進(jìn)程托管的情況,但是通過ps -ef <container id>無法查到對(duì)應(yīng)的運(yùn)行進(jìn)程。哎,后來開始開始查supervisor以及Dockerfile中的進(jìn)程,都沒有。這種情況的可能原因是容器啟動(dòng)之后,之后,主機(jī)因任何原因重新啟動(dòng)并且沒有優(yōu)雅地終止容器。剩下的文件現(xiàn)在阻止你重新生成舊名稱的新容器,因?yàn)橄到y(tǒng)認(rèn)為舊容器仍然存在。
# 刪除容器
$ sudo docker rm -f f8e8c3..
Error response from daemon: Conflict, cannot remove the default name of the container
-
[解決方法] 找到 /var/lib/docker/containers/下的對(duì)應(yīng)容器的文件夾,將其刪除,然后重啟一下dockerd即可。我們會(huì)發(fā)現(xiàn),之前無法刪除的容器沒有了。
# 刪除容器文件
$ sudo rm -rf /var/lib/docker/containers/f8e8c3...65720
# 重啟服務(wù)
$ sudo systemctl restart docker.service
Part7Docker 容器中文異常
容器存在問題話,記得優(yōu)先在官網(wǎng)查詢
-
[問題起因] 今天登陸之前部署的 MySQL數(shù)據(jù)庫查詢,發(fā)現(xiàn)使用SQL語句無法查詢中文字段,即使直接輸入中文都沒有辦法顯示。
# 查看容器支持的字符集
root@b18f56aa1e15:# locale -a
C
C.UTF-8
POSIX
-
[解決方法] Docker部署的MySQL系統(tǒng)使用的是POSIX字符集。然而POSIX字符集是不支持中文的,而C.UTF-8是支持中文的只要把系統(tǒng)中的環(huán)境LANG改為"C.UTF-8"格式即可解決問題。同理,在K8S進(jìn)入pod不能輸入中文也可用此方法解決。
# 臨時(shí)解決
docker exec -it some-mysql env LANG=C.UTF-8 /bin/bash
# 永久解決
docker run --name some-mysql \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-d mysql:tag --character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
Part8Docker 容器網(wǎng)絡(luò)互通
了解 Docker 的四種網(wǎng)絡(luò)模型
-
[問題起因] 在本機(jī)部署 Nginx容器想代理本機(jī)啟動(dòng)的Python后端服務(wù)程序,但是對(duì)代碼服務(wù)如下的配置,結(jié)果訪問的時(shí)候一直提示502錯(cuò)誤。
# 啟動(dòng)Nginx服務(wù)
$ docker run -d -p 80:80 $PWD:/etc/nginx nginx
server {
...
location /api {
proxy_pass http://localhost:8080
}
...
}
-
[解決方法] 后面發(fā)現(xiàn)是因?yàn)? nginx.conf配置文件中的localhost配置的有問題,由于Nginx是在容器中運(yùn)行,所以localhost為容器中的localhost,而非本機(jī)的localhost,所以導(dǎo)致無法訪問。 -
可以將 nginx.conf中的localhost改為宿主機(jī)的IP地址,就可以解決502的錯(cuò)誤。
# 查詢宿主機(jī)IP地址 => 172.17.0.1
$ ip addr show docker0
docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:d5:4c:f2:1e brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:d5ff:fe4c:f21e/64 scope link
valid_lft forever preferred_lft forever
server {
...
location /api {
proxy_pass http://172.17.0.1:8080
}
...
}
-
當(dāng)容器使用 host網(wǎng)絡(luò)時(shí),容器與宿主共用網(wǎng)絡(luò),這樣就能在容器中訪問宿主機(jī)網(wǎng)絡(luò),那么容器的localhost就是宿主機(jī)的localhost了。
# 服務(wù)的啟動(dòng)方式有所改變(沒有映射出來端口)
# 因?yàn)楸旧砼c宿主機(jī)共用了網(wǎng)絡(luò),宿主機(jī)暴露端口等同于容器中暴露端口
$ docker run -d -p 80:80 --network=host $PWD:/etc/nginx nginxx
Part9Docker 容器總線錯(cuò)誤
總線錯(cuò)誤看到的時(shí)候還是挺嚇人了
-
[問題起因] 在 docker容器中運(yùn)行程序的時(shí)候,提示bus error錯(cuò)誤。
# 總線報(bào)錯(cuò)
$ inv app.user_op --name=zhangsan
Bus error (core dumped)
-
[解決方法] 原因是在 docker運(yùn)行的時(shí)候,shm分區(qū)設(shè)置太小導(dǎo)致share memory不夠。不設(shè)置–shm-size參數(shù)時(shí),docker給容器默認(rèn)分配的shm大小為64M,導(dǎo)致程序啟動(dòng)時(shí)不足。
# 啟動(dòng)docker的時(shí)候加上--shm-size參數(shù)(單位為b,k,m或g)
$ docker run -it --rm --shm-size=200m pytorch/pytorch:latest
-
[解決方法] 還有一種情況就是容器內(nèi)的磁盤空間不足,也會(huì)導(dǎo)致 bus error的報(bào)錯(cuò),所以清除多余文件或者目錄,就可以解決了。
# 磁盤空間不足
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 1T 1T 0G 100% /
shm tmpfs 64M 24K 64M 1% /dev/shm
Part10Docker NFS 掛載報(bào)錯(cuò)
總線錯(cuò)誤看到的時(shí)候還是挺嚇人了
-
[問題起因] 我們將服務(wù)部署到 openshift集群中,啟動(dòng)服務(wù)調(diào)用資源文件的時(shí)候,報(bào)錯(cuò)信息如下所示。從報(bào)錯(cuò)信息中,得知是在Python3程序執(zhí)行read_file()讀取文件的內(nèi)容,給文件加鎖的時(shí)候報(bào)錯(cuò)了。但是奇怪的是,本地調(diào)試的時(shí)候發(fā)現(xiàn)服務(wù)都是可以正常運(yùn)行的,文件加鎖也是沒問題的。后來發(fā)現(xiàn),在openshift集群中使用的是NFS掛 載的共享磁盤。
# 報(bào)錯(cuò)信息
Traceback (most recent call last):
......
File "xxx/utils/storage.py", line 34, in xxx.utils.storage.LocalStorage.read_file
OSError: [Errno 9] Bad file descriptor
# 文件加鎖代碼
...
with open(self.mount(path), 'rb') as fileobj:
fcntl.flock(fileobj, fcntl.LOCK_EX)
data = fileobj.read()
return data
...
-
[解決方法] 從下面的信息得知,要在 Linux中使用flock()的話,就需要升級(jí)內(nèi)核版本到2.6.11+才行。后來才發(fā)現(xiàn),這實(shí)際上是由RedHat內(nèi)核中的一個(gè)錯(cuò)誤引起的,并在kernel-3.10.0-693.18.1.el7版本中得到修復(fù)。所以對(duì)于NFSv3和NFSv4服務(wù)而已,就需要升級(jí)Linux內(nèi)核版本才能夠解決這個(gè)問題。
# https://t.codebug.vip/questions-930901.htm
$ In Linux kernels up to 2.6.11, flock() does not lock files over NFS (i.e.,
the scope of locks was limited to the local system). [...] Since Linux 2.6.12,
NFS clients support flock() locks by emulating them as byte-range locks on the entire file.
Part11Docker 默認(rèn)使用網(wǎng)段
啟動(dòng)的容器網(wǎng)絡(luò)無法相互通信,很是奇怪!
-
[問題起因] 我們?cè)谑褂? Docker啟動(dòng)服務(wù)的時(shí)候,發(fā)現(xiàn)有時(shí)候服務(wù)之前可以相互連通,而有時(shí)間啟動(dòng)的多個(gè)服務(wù)之前卻出現(xiàn)了無法訪問的情況。究其原因,發(fā)現(xiàn)原來是因?yàn)槭褂玫膬?nèi)部私有地址網(wǎng)段不一致導(dǎo)致的。有點(diǎn)服務(wù)啟動(dòng)到了172.17 - 172.31的網(wǎng)段,有的服務(wù)跑到了192.169.0 - 192.168.224的網(wǎng)段,這樣導(dǎo)致服務(wù)啟動(dòng)之后出現(xiàn)無法訪問的情況。

-
[解決方法] 上述問題的處理方式,就是手動(dòng)指定 Docker服務(wù)的啟動(dòng)網(wǎng)段,就可以了。
# 查看docker容器配置
$ cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"],
"default-address-pools":[{"base":"172.17.0.0/12","size":24}],
"experimental": true,
"default-runtime": "nvidia",
"live-restore": true,
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
Part12Docker 服務(wù)啟動(dòng)串臺(tái)
使用 docker-compose 命令各自啟動(dòng)兩組服務(wù),發(fā)現(xiàn)服務(wù)會(huì)串臺(tái)!
-
[問題起因] 在兩個(gè)不同名稱的目錄目錄下面,使用 docker-compose來啟動(dòng)服務(wù),發(fā)現(xiàn)當(dāng)A組服務(wù)啟動(dòng)完畢之后,再啟動(dòng)B組服務(wù)的時(shí)候,發(fā)現(xiàn)A組當(dāng)中對(duì)應(yīng)的一部分服務(wù)又重新啟動(dòng)了一次,這就非常奇怪了!因?yàn)檫@個(gè)問題的存在會(huì)導(dǎo)致,A組服務(wù)和B組服務(wù)無法同時(shí)啟動(dòng)。之前還以為是工具的Bug,后來請(qǐng)教了“上峰”,才知道了原因,恍然大悟。
# 服務(wù)目錄結(jié)構(gòu)如下所示
A: /data1/app/docker-compose.yml
B: /data2/app/docker-compose.yml
-
[解決方法] 發(fā)現(xiàn) A和B兩組服務(wù)會(huì)串臺(tái)的原因,原來是docker-compose會(huì)給啟動(dòng)的容器加label標(biāo)簽,然后根據(jù)這些label標(biāo)簽來識(shí)別和判斷對(duì)應(yīng)的容器服務(wù)是由誰啟動(dòng)的、誰來管理的,等等。而這里,我們需要關(guān)注的label變量是com.docker.compose.project,其對(duì)應(yīng)的值是使用啟動(dòng)配置文件的目錄的最底層子目錄名稱,即上面的app就是對(duì)應(yīng)的值。我們可以發(fā)現(xiàn),A和B兩組服務(wù)對(duì)應(yīng)的值都是app,所以啟動(dòng)的時(shí)候被認(rèn)為是同一個(gè),這就出現(xiàn)了上述的問題。如果需要深入了解的話,可以去看對(duì)應(yīng)源代碼。

# 可以將目錄結(jié)構(gòu)調(diào)整為如下所示
A: /data/app1/docker-compose.yml
B: /data/app2/docker-compose.yml
A: /data1/app-old/docker-compose.yml
B: /data2/app-new/docker-compose.yml
-
或者使用 docker-compose命令提供的參數(shù)-p來規(guī)避該問題的發(fā)生。
# 指定項(xiàng)目項(xiàng)目名稱
$ docker-compose -f ./docker-compose.yml -p app1 up -d
Part13Docker 命令調(diào)用報(bào)錯(cuò)
在編寫腳本的時(shí)候常常會(huì)執(zhí)行 docker 相關(guān)的命令,但是需要注意使用細(xì)節(jié)!
-
[問題起因] CI更新環(huán)境執(zhí)行了一個(gè)腳本,但是腳本執(zhí)行過程中報(bào)錯(cuò)了,如下所示。通過對(duì)應(yīng)的輸出信息,可以看到提示說正在執(zhí)行的設(shè)備不是一個(gè)tty。

-
隨即,查看了腳本發(fā)現(xiàn)報(bào)錯(cuò)地方是執(zhí)行了一個(gè) exec的docker命令,大致如下所示。很奇怪的是,手動(dòng)執(zhí)行或直接調(diào)腳本的時(shí)候,怎么都是沒有問題的,但是等到CI調(diào)用的時(shí)候怎么都是有問題。后來好好看下下面這個(gè)命令,注意到-it這個(gè)參數(shù)了。
# 腳本調(diào)用docker命令
docker exec -it <container_name> psql -Upostgres ......
-
我們可以一起看下 exec命令的這兩個(gè)參數(shù),自然就差不多理解了。
| 編號(hào) | 參數(shù) | 解釋說明 |
|---|---|---|
| 1 | -i/-interactive |
即使沒有附加也保持 STDIN 打開;如果你需要執(zhí)行命令則需要開啟這個(gè)選項(xiàng) |
| 2 | -t/–tty |
分配一個(gè)偽終端進(jìn)行執(zhí)行;一個(gè)連接用戶的終端與容器 stdin 和 stdout 的橋梁 |
-
[解決方法] docker exec的參數(shù)-t是指Allocate a pseudo-TTY的意思,而CI在執(zhí)行job的時(shí)候并不是在TTY終端中執(zhí)行,所以-t這個(gè)參數(shù)會(huì)報(bào)錯(cuò)。同時(shí)在 『stackoverflow』也有人給出原因,可以自行查看。

Part14Docker 定時(shí)任務(wù)異常
在 Crontab 定時(shí)任務(wù)中也存在 Docker 命令執(zhí)行異常的情況!
-
[問題起因] 今天發(fā)現(xiàn)了一個(gè)問題,就是在備份 Mysql數(shù)據(jù)庫的時(shí)候,使用docker容器進(jìn)行備份,然后使用Crontab定時(shí)任務(wù)來觸發(fā)備份。但是發(fā)現(xiàn)備份的MySQL數(shù)據(jù)庫居然是空的,但是手動(dòng)執(zhí)行對(duì)應(yīng)命令切是好的,很奇怪。
# Crontab定時(shí)任務(wù)
0 */6 * * * \
docker exec -it <container_name> sh -c \
'exec mysqldump --all-databases -uroot -ppassword ......'
-
[解決方法] 后來發(fā)現(xiàn)是因?yàn)閳?zhí)行的 docker命令多個(gè)-i導(dǎo)致的。因?yàn)?Crontab命令執(zhí)行的時(shí)候,并不是交互式的,所以需要把這個(gè)去掉才可以??偨Y(jié)就是,如果你需要回顯的話則需要-t選項(xiàng),如果需要交互式會(huì)話則需要-i選項(xiàng)。
| 編號(hào) | 參數(shù) | 解釋說明 |
|---|---|---|
| 1 | -i/-interactive |
即使沒有附加也保持 STDIN 打開;如果你需要執(zhí)行命令則需要開啟這個(gè)選項(xiàng) |
| 2 | -t/–tty |
分配一個(gè)偽終端進(jìn)行執(zhí)行;一個(gè)連接用戶的終端與容器 stdin 和 stdout 的橋梁 |
Part15Docker 變量使用引號(hào)
compose 里邊環(huán)境變量帶不帶引號(hào)的問題!
-
[問題起因] 使用過 compose的同學(xué)可能都遇到過,我們?cè)诰帉憜?dòng)配置文件的時(shí)候,添加環(huán)境變量的時(shí)候到底是使用單引號(hào)、雙引號(hào)還是不使用引號(hào)。時(shí)間長了,可能我們總是三者是一樣的,可以相互使用。但是,直到最后我們發(fā)現(xiàn)坑越來越多,越來越隱晦。 -
反正我是遇到過很多是因?yàn)樘砑右?hào)導(dǎo)致的服務(wù)啟動(dòng)問題,后來得出的結(jié)論就是一律不適用引號(hào)。裸奔,體驗(yàn)前所未有的爽快!直到現(xiàn)在看到了 Github中對(duì)應(yīng)的 issus 之后,才終于破案了。
# TESTVAR="test"
在Compose中進(jìn)行引用TESTVAR變量,無法找到
# TESTVAR=test
在Compose中進(jìn)行引用TESTVAR變量,可以找到
# docker run -it --rm -e TESTVAR="test" test:latest
后來發(fā)現(xiàn)docker本身其實(shí)已經(jīng)正確地處理了引號(hào)的使用
-
[解決方法] 得到的結(jié)論就是,因?yàn)? Compose解析yaml配置文件,發(fā)現(xiàn)引號(hào)也進(jìn)行了解釋包裝。這就導(dǎo)致原本的TESTVAR="test"被解析成了'TESTVAR="test"',所以我們?cè)谝玫臅r(shí)候就無法獲取到對(duì)應(yīng)的值。現(xiàn)在解決方法就是,不管是我們直接在配置文件添加環(huán)境變量或者使用env_file配置文件,能不使用引號(hào)就不適用引號(hào)。
Part16Docker 刪除鏡像報(bào)錯(cuò)
無法刪除鏡像,歸根到底還是有地方用到了!
-
[問題起因] 清理服器磁盤空間的時(shí)候,刪除某個(gè)鏡像的時(shí)候提示如下信息。提示需要強(qiáng)制刪除,但是發(fā)現(xiàn)及時(shí)執(zhí)行了強(qiáng)制刪除依舊沒有效果。
# 刪除鏡像
$ docker rmi 3ccxxxx2e862
Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images
# 強(qiáng)制刪除
$ dcoker rmi -f 3ccxxxx2e862
Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images
-
[解決方法] 后來才發(fā)現(xiàn),出現(xiàn)這個(gè)原因主要是因?yàn)? TAG,即存在其他鏡像引用了這個(gè)鏡像。這里我們可以使用如下命令查看對(duì)應(yīng)鏡像文件的依賴關(guān)系,然后根據(jù)對(duì)應(yīng)TAG來刪除鏡像。
# 查詢依賴 - image_id表示鏡像名稱
$ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=<image_id>)
# 根據(jù)TAG刪除鏡像
$ docker rmi -f c565xxxxc87f
# 刪除懸空鏡像
$ docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
Part17Docker 普通用戶切換
切換 Docker 啟動(dòng)用戶的話,還是需要注意下權(quán)限問題的!
-
[問題起因] 我們都知道在 Docker容器里面使用root用戶的話,是不安全的,很容易出現(xiàn)越權(quán)的安全問題,所以一般情況下,我們都會(huì)使用普通用戶來代替root進(jìn)行服務(wù)的啟動(dòng)和管理的。今天給一個(gè)服務(wù)切換用戶的時(shí)候,發(fā)現(xiàn)Nginx服務(wù)一直無法啟動(dòng),提示如下權(quán)限問題。因?yàn)閷?duì)應(yīng)的配置文件也沒有配置var相關(guān)的目錄,無奈 ???♀ !?
# Nginx報(bào)錯(cuò)信息
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
2020/11/12 15:25:47 [emerg] 23#23: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
-
[解決方法] 后來發(fā)現(xiàn)還是 nginx.conf配置文件,配置的有問題,需要將Nginx服務(wù)啟動(dòng)時(shí)候需要的文件都配置到一個(gè)無權(quán)限的目錄,即可解決。
user www-data;
worker_processes 1;
error_log /data/logs/master_error.log warn;
pid /dev/shm/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
gzip on;
sendfile on;
tcp_nopush on;
keepalive_timeout 65;
client_body_temp_path /tmp/client_body;
fastcgi_temp_path /tmp/fastcgi_temp;
proxy_temp_path /tmp/proxy_temp;
scgi_temp_path /tmp/scgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
include /etc/nginx/conf.d/*.conf;
}
Part18Docker 綁定到 IPv6 上
Docker 服務(wù)在啟動(dòng)的時(shí)候,將地址綁定到 IPv6 地址上面了,提示報(bào)錯(cuò)信息!
-
[問題起因] 物理機(jī)器更新了對(duì)應(yīng)補(bǔ)丁之后,重啟了服務(wù),導(dǎo)致原本可以正常啟動(dòng)的 docker-compose服務(wù)提示如下報(bào)錯(cuò)信息。不清楚是否修改了操作系統(tǒng)的相關(guān)配置,還是對(duì)應(yīng)docker進(jìn)行的其他方面的配置,比如修改/etc/docker/daemon.json或者docker的service啟動(dòng)文件。
# Docker的報(bào)錯(cuò)信息
docker run -p 80:80 nginx:alpine succeeds. Previously, this was failing with Error \
starting userland proxy: listen tcp6 [::]:80: socket: address family not supported by protocol.
-
[解決方法] 通過如上所示的報(bào)錯(cuò)信息,可以看到服務(wù)的啟動(dòng)端口綁定到了 tcp6上面了,但是對(duì)應(yīng)的socket發(fā)現(xiàn)系統(tǒng)本身并不支持。這時(shí),我們一看下對(duì)應(yīng)的操作系統(tǒng)ipv6的設(shè)置,發(fā)現(xiàn)系統(tǒng)禁用了,所有的ipv6地址。需要了解的朋友,可以參考 fix port forwarding with ipv6.disable=1 和 cannot start if ipv6 is disabled on host 這兩個(gè)issus來獲取更多信息。
# 操作系統(tǒng)配置
$ cat /etc/sysctl.conf | grep ipv6
net.ipv6.conf.all.disable_ipv6=1
-
[方法一] 最為簡單的解決方法,就是在 docker-compose.yml文件中,手動(dòng)指定將對(duì)應(yīng)服務(wù)的端口綁定到ipv4上面,如下所示。
version: "3"
services:
app:
restart: on-failure
container_name: app_web
image: app:latest
ports:
- "0.0.0.0:80:80/tcp"
volumes:
- "./app_web:/data"
networks:
- app_network
networks:
app_network:
-
[方法二] 或者修改 /etc/docker/daemon.json文件,在配置中,阻止Docker錯(cuò)誤的將端口映射到IPv6上,即可達(dá)到同樣的效果,且不用再次修改多個(gè)服務(wù)的啟動(dòng)配置文件了。
# 修改配置
$ vim /etc/docker/daemon.json
{
"ipv6": false,
"fixed-cidr-v6": "2001:db8:1::/64"
}
# 重啟服務(wù)
$ systemctl reload docker
-
[方法三] Docker默認(rèn)情況下會(huì)同時(shí)將端口映射于IPv4與IPv6兩者上,而且有的時(shí)候會(huì)出現(xiàn)只綁定到了IPv6,導(dǎo)致服務(wù)無法正常訪問的情況?,F(xiàn)在通用的始終還是IPv4地址,因此最簡單的做法就是關(guān)閉IPv6地址。詳細(xì)的配置,可以參考 Port redirecting binding to IPv6 but not IPv4 interfaces 這個(gè)issus地址。
# 修改系統(tǒng)配置
echo '1' > /proc/sys/net/ipv6/conf/lo/disable_ipv6
echo '1' > /proc/sys/net/ipv6/conf/lo/disable_ipv6
echo '1' > /proc/sys/net/ipv6/conf/all/disable_ipv6
echo '1' > /proc/sys/net/ipv6/conf/default/disable_ipv6
# 重啟網(wǎng)絡(luò)
$ /etc/init.d/networking restart
# 最后檢測是否已關(guān)閉IPv6
ip addr show | grep net6
Part19Docker 容器啟動(dòng)超時(shí)
Docker 服務(wù)在啟動(dòng)的時(shí)候,提示超時(shí),被直接終止了!
-
[問題起因] 使用 docker-compose啟動(dòng)容器的時(shí)候,等待了很久的時(shí)候(大約2-3分鐘左右),之后提示如下信息。通過閱讀信息內(nèi)容,可以看到是因?yàn)槌瑫r(shí)導(dǎo)致的,提示可以通過設(shè)置環(huán)境變量,加大超時(shí)的時(shí)間。
$ docker-compose up -d
ERROR: for xxx UnixHTTPConnectionPool(host='localhost', port=None): Read timed out. (read timeout=70)
ERROR: An HTTP request took too long to complete. Retry with --verbose to obtain debug information.
If you encounter this issue regularly because of slow network conditions, consider setting COMPOSE_HTTP_TIMEOUT to a higher value (current value: 60).
-
[解決方法] 按照提示設(shè)置的環(huán)境變量之后,再次啟動(dòng)發(fā)現(xiàn)確實(shí)可以正常啟動(dòng)了,但是還是能夠感覺到有些慢。
$ sudo vim /etc/profile
export COMPOSE_HTTP_TIMEOUT=500
export DOCKER_CLIENT_TIMEOUT=500
-
排除了下啟動(dòng)流程,因?yàn)槿萜鲉?dòng)有映射目錄到容器里面且目錄大小比較大,所以懷疑是因?yàn)? i/o導(dǎo)致的。隨即使用iotop命令查看服務(wù)器目前的i/o情況,發(fā)現(xiàn)存在很多個(gè)rg命令,且都處于100%左右。查了下,發(fā)現(xiàn)是vscode遠(yuǎn)程服務(wù)器啟動(dòng)的搜索目錄結(jié)構(gòu)的進(jìn)程,西八,有些坑呀!
$ sudo iotop
4269 be/4 escape 15.64 K/s 0.00 B/s 0.00 % 98.36 % rg --files --hidden
4270 be/4 escape 28.15 K/s 0.00 B/s 0.00 % 97.46 % rg --files --hidden
4272 be/4 escape 31.27 K/s 0.00 B/s 0.00 % 97.39 % rg --files --hidden
4276 be/4 escape 34.40 K/s 0.00 B/s 0.00 % 96.98 % rg --files --hidden
-
| 更多精彩文章 -
![]()
▽加我微信,交個(gè)朋友 長按/掃碼添加↑↑↑


