這裡主要是為了記錄在使用 Docker 的時候遇到的問題及其處了解決方法。
Docker疑難雜症彙總
Docker疑難雜症彙總
1. Docker 遷移存儲目錄
預設情況系統會将 Docker 容器存放在/var/lib/docker 目錄下
[問題起因] 今天通過監控系統,發現公司其中一台伺服器的磁盤快慢,随即上去看了下,發現
/var/lib/docker
這個目錄特别大。由上述原因,我們都知道,在
/var/lib/docker
中存儲的都是相關于容器的存儲,是以也不能随便的将其删除掉。
那就準備遷移
docker
的存儲目錄吧,或者對
/var
裝置進行擴容來達到相同的目的。更多關于
dockerd
的詳細參數。
但是需要注意的一點就是,盡量不要用軟鍊, 因為一些
docker
容器編排系統不支援這樣做,比如我們所熟知的
k8s
就在内。
# 發現容器啟動不了了
ERROR:cannot create temporary directory!
# 檢視系統存儲情況
$ du -h --max-depth=1
複制
[解決方法 1] 添加軟連結
# 1.停止docker服務
$ sudo systemctl stop docker
# 2.開始遷移目錄
$ sudo mv /var/lib/docker /data/
# 3.添加軟連結
$ sudo ln -s /data/docker /var/lib/docker
# 4.啟動docker服務
$ sudo systemctl start docker
複制
[解決方法 2] 改動 docker 配置檔案
# 3.改動docker啟動配置檔案
$ sudo vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --graph=/data/docker/
# 3.改動docker啟動配置檔案
$ sudo vim /etc/docker/daemon.json
{
"live-restore": true,
"graph": [ "/data/docker/" ]
}
複制
[操作注意事項] 在遷移
docker
目錄的時候注意使用的指令,要麼使用
mv
指令直接移動,要麼使用
cp
指令複制檔案,但是需要注意同時複制檔案權限和對應屬性,不然在使用的時候可能會存在權限問題。如果容器中,也是使用
root
使用者,則不會存在該問題,但是也是需要按照正确的操作來遷移目錄。
# 使用mv指令
$ sudo mv /var/lib/docker /data/docker
# 使用cp指令
$ sudo cp -arv /data/docker /data2/docker
複制
下圖中,就是因為啟動的容器使用的是普通使用者運作程序的,且在運作當中需要使用
/tmp
目錄,結果提示沒有權限。在我們導入容器鏡像的時候,其實是會将容器啟動時需要的各個目錄的權限和屬性都賦予了。如果我們直接是
cp
指令單純複制檔案内容的話,就會出現屬性不一緻的情況,同時還會有一定的安全問題。
Docker遷移存儲目錄
2. Docker 裝置空間不足
Increase Docker container size from default 10GB on rhel7.
[問題起因一] 容器在導入或者啟動的時候,如果提示磁盤空間不足的,那麼多半是真的因為實體磁盤空間真的有問題導緻的。如下所示,我們可以看到
/
分區确實滿了。
# 檢視實體磁盤空間
$ 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
複制
如果發現真的是實體磁盤空間滿了的話,就需要檢視到底是什麼占據了如此大的空間,導緻因為容器沒有空間無法啟動。其中,
docker
自帶的指令就是一個很好的能夠幫助我們發現問題的工具。
# 檢視基本資訊
# 硬體驅動使用的是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
複制
[解決方法]通過檢視資訊,我們知道正是因為
docker
可用的磁盤空間不足,是以導緻啟動的時候沒有足夠的空間進行加載啟動鏡像。解決的方法也很簡單,第一就是清理無效資料檔案釋放磁盤空間
(清除日志)
,第二就是修改
docker
資料的存放路徑
(大分區)
。
# 顯示哪些容器目錄具有最大的日志檔案
$ du -d1 -h /var/lib/docker/containers | sort -h
# 清除您選擇的容器日志檔案的内容
$ cat /dev/null > /var/lib/docker/containers/container_id/container_log_name
複制
[問題起因二]顯然我遇到的不是上一種情況,而是在啟動容器的時候,容器啟動之後不久就顯示是
unhealthy
的狀态,通過如下日志發現,原來是複制配置檔案啟動的時候,提示磁盤空間不足。
後面發現是因為
CentOS7
的系統使用的
docker
容器預設的建立大小就是
10G
而已,然而我們使用的容器卻超過了這個限制,導緻無法啟動時提示空間不足。
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] 改動 docker 啟動配置檔案
# /etc/docker/daemon.json
{
"live-restore": true,
"storage-opt": [ "dm.basesize=20G" ]
}
複制
[解決方法 2] 改動 systemctl 的 docker 啟動檔案
# 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
複制
[問題起因三]還有一種情況也會讓容器無法啟動,并提示磁盤空間不足,但是使用指令檢視發現并不是因為實體磁盤真的不足導緻的。而是,因為對于分區的
inode
節點數滿了導緻的。
# 報錯資訊
No space left on device
複制
[解決方法]因為
ext3
檔案系統使用
inode table
存儲
inode
資訊,而
xfs
檔案系統使用
B+ tree
來進行存儲。考慮到性能問題,預設情況下這個
B+ tree
隻會使用前
1TB
空間,當這
1TB
空間被寫滿後,就會導緻無法寫入
inode
資訊,報磁盤空間不足的錯誤。我們可以在
mount
時,指定
inode64
即可将這個
B+ tree
使用的空間擴充到整個檔案系統。
# 檢視系統的inode節點使用情況
$ sudo df -i
# 嘗試重新挂載
$ sudo mount -o remount -o noatime,nodiratime,inode64,nobarrier /dev/vda1
複制
[補充知識]檔案儲存在硬碟上,硬碟的最小存儲機關叫做
“扇區”(Sector)
。每個扇區儲存
512
位元組(相當于
0.5KB
)。作業系統讀取硬碟的時候,不會一個個扇區地讀取,這樣效率太低,而是一次性連續讀取多個扇區,即一次性讀取一個
“塊”(block)
。這種由多個扇區組成的”塊”,是檔案存取的最小機關。”塊”的大小,最常見的是
4KB
,即連續八個
sector
組成一個
block
塊。檔案資料都儲存在”塊”中,那麼很顯然,我們還必須找到一個地方儲存檔案的元資訊,比如檔案的建立者、檔案的建立日期、檔案的大小等等。這種儲存檔案元資訊的區域就叫做
“索引節點”(inode)
。每一個檔案都有對應的
inode
,裡面包含了除了檔案名以外的所有檔案資訊。
inode
也會消耗硬碟空間,是以硬碟格式化的時候,作業系統自動将硬碟分成兩個區域。一個是資料區,存放檔案資料;另一個是
inode
區(
inode table
),存放
inode
所包含的資訊。每個
inode
節點的大小,一般是
128
位元組或
256
位元組。
inode
節點的總數,在格式化時就給定,一般是每
1KB
或每
2KB
就設定一個
inode
節點。
# 每個節點資訊的内容
$ 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
複制
3. Docker 缺共享連結庫
Docker 指令需要對/tmp 目錄下面有通路權限
[問題起因] 給系統安裝完
compose
之後,檢視版本的時候,提示缺少一個名為
libz.so.1
的共享連結庫。第一反應就是,是不是系統少安裝那個軟體包導緻的。随即,搜尋了一下,将相關的依賴包都給安裝了,卻還是提示同樣的問題。
# 提示錯誤資訊
$ docker-compose --version
error while loading shared libraries: libz.so.1: failed to map segment from shared object: Operation not permitted
複制
[解決方法] 後來發現,是因為系統中
docker
沒有對
/tmp
目錄的通路權限導緻,需要重新将其挂載一次,就可以解決了。
# 重新挂載
$ sudo mount /tmp -o remount,exec
複制
4. Docker 容器檔案損壞
對 dockerd 的配置有可能會影響到系統穩定
[問題起因] 容器檔案損壞,經常會導緻容器無法操作。正常的
docker
指令已經無法操控這台容器了,無法關閉、重新開機、删除。正巧,前天就需要這個的問題,主要的原因是因為重新對
docker
的預設容器進行了重新的配置設定限制導緻的。
# 操作容器遇到類似的錯誤
b'devicemapper: Error running deviceCreate (CreateSnapDeviceRaw) dm_task_run failed'
複制
[解決方法] 可以通過以下操作将容器删除/重建。
# 1.關閉docker
$ sudo systemctl stop docker
# 2.删除容器檔案
$ sudo rm -rf /var/lib/docker/containers
# 3.重新整理容器中繼資料
$ 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
複制
5. Docker 容器優雅重新開機
不停止伺服器上面運作的容器,重新開機 dockerd 服務是多麼好的一件事
[問題起因] 預設情況下,當
Docker
守護程式終止時,它會關閉正在運作的容器。從
Docker-ce 1.12
開始,可以在配置檔案中添加
live-restore
參數,以便在守護程式變得不可用時容器保持運作。需要注意的是
Windows
平台暫時還是不支援該參數的配置。
# Keep containers alive during daemon downtime
$ sudo vim /etc/docker/daemon.yaml
{
"live-restore": true
}
# 在守護程序停機期間保持容器存活
$ sudo dockerd --live-restore
# 隻能使用reload重載
# 相當于發送SIGHUP信号量給dockerd守護程序
$ sudo systemctl reload docker
# 但是對應網絡的設定需要restart才能生效
$ sudo systemctl restart docker
複制
[解決方法] 可以通過以下操作将容器删除/重建。
# /etc/docker/daemon.yaml
{
"registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"], # 配置擷取官方鏡像的倉庫位址
"experimental": true, # 啟用實驗功能
"default-runtime": "nvidia", # 容器的預設OCI運作時(預設為runc)
"live-restore": true, # 重新開機dockerd服務的時候容易不終止
"runtimes": { # 配置容器運作時
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-address-pools": [ # 配置容器使用的子網位址池
{
"scope": "local",
"base":"172.17.0.0/12",
"size":24
}
]
}
複制
6. Docker 容器無法删除
找不到對應容器程序是最吓人的
[問題起因] 今天遇到
docker
容器無法停止/終止/删除,以為這個容器可能又出現了
dockerd
守護程序托管的情況,但是通過
ps -ef <container id>
無法查到對應的運作程序。哎,後來開始開始查
supervisor
以及
Dockerfile
中的程序,都沒有。這種情況的可能原因是容器啟動之後,之後,主機因任何原因重新啟動并且沒有優雅地終止容器。剩下的檔案現在阻止你重新生成舊名稱的新容器,因為系統認為舊容器仍然存在。
# 删除容器
$ sudo docker rm -f f8e8c3..
Error response from daemon: Conflict, cannot remove the default name of the container
複制
[解決方法] 找到
/var/lib/docker/containers/
下的對應容器的檔案夾,将其删除,然後重新開機一下
dockerd
即可。我們會發現,之前無法删除的容器沒有了。
# 删除容器檔案
$ sudo rm -rf /var/lib/docker/containers/f8e8c3...65720
# 重新開機服務
$ sudo systemctl restart docker.service
複制
7. Docker 容器中文異常
容器存在問題話,記得優先在官網查詢
[問題起因] 今天登陸之前部署的
MySQL
資料庫查詢,發現使用
SQL
語句無法查詢中文字段,即使直接輸入中文都沒有辦法顯示。
# 檢視容器支援的字元集
root@b18f56aa1e15:# locale -a
C
C.UTF-8
POSIX
複制
[解決方法]
Docker
部署的
MySQL
系統使用的是
POSIX
字元集。然而
POSIX
字元集是不支援中文的,而
C.UTF-8
是支援中文的隻要把系統中的環境
LANG
改為
"C.UTF-8"
格式即可解決問題。同理,在
K8S
進入
pod
不能輸入中文也可用此方法解決。
# 臨時解決
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
複制
8. Docker 容器網絡互通
了解 Docker 的四種網絡模型
[問題起因] 在本機部署
Nginx
容器想代理本機啟動的
Python
後端服務程式,但是對代碼服務如下的配置,結果通路的時候一直提示
502
錯誤。
# 啟動Nginx服務
$ docker run -d -p 80:80 $PWD:/etc/nginx nginx
server {
...
location /api {
proxy_pass http://localhost:8080
}
...
}
複制
[解決方法] 後面發現是因為
nginx.conf
配置檔案中的
localhost
配置的有問題,由于
Nginx
是在容器中運作,是以
localhost
為容器中的
localhost
,而非本機的
localhost
,是以導緻無法通路。
可以将
nginx.conf
中的
localhost
改為主控端的
IP
位址,就可以解決
502
的錯誤。
# 查詢主控端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
}
...
}
複制
當容器使用
host
網絡時,容器與宿主共用網絡,這樣就能在容器中通路主控端網絡,那麼容器的
localhost
就是主控端的
localhost
了。
# 服務的啟動方式有所改變(沒有映射出來端口)
# 因為本身與主控端共用了網絡,主控端暴露端口等同于容器中暴露端口
$ docker run -d -p 80:80 --network=host $PWD:/etc/nginx nginxx
複制
9. Docker 容器總線錯誤
總線錯誤看到的時候還是挺吓人了
[問題起因] 在
docker
容器中運作程式的時候,提示
bus error
錯誤。
# 總線報錯
$ inv app.user_op --name=zhangsan
Bus error (core dumped)
複制
[解決方法] 原因是在
docker
運作的時候,
shm
分區設定太小導緻
share memory
不夠。不設定
–shm-size
參數時,
docker
給容器預設配置設定的
shm
大小為
64M
,導緻程式啟動時不足。
# 啟動docker的時候加上--shm-size參數(機關為b,k,m或g)
$ docker run -it --rm --shm-size=200m pytorch/pytorch:latest
複制
[解決方法] 還有一種情況就是容器内的磁盤空間不足,也會導緻
bus error
的報錯,是以清除多餘檔案或者目錄,就可以解決了。
# 磁盤空間不足
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 1T 1T 0G 100% /
shm tmpfs 64M 24K 64M 1% /dev/shm
複制
10. Docker NFS 挂載報錯
總線錯誤看到的時候還是挺吓人了
[問題起因] 我們将服務部署到
openshift
叢集中,啟動服務調用資源檔案的時候,報錯資訊如下所示。從報錯資訊中,得知是在
Python3
程式執行
read_file()
讀取檔案的内容,給檔案加鎖的時候報錯了。但是奇怪的是,本地調試的時候發現服務都是可以正常運作的,檔案加鎖也是沒問題的。後來發現,在
openshift
叢集中使用的是
NFS
挂載的共享磁盤。
# 報錯資訊
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()
的話,就需要更新核心版本到
2.6.11+
才行。後來才發現,這實際上是由
RedHat
內核中的一個錯誤引起的,并在
kernel-3.10.0-693.18.1.el7
版本中得到修複。是以對于
NFSv3
和
NFSv4
服務而已,就需要更新
Linux
核心版本才能夠解決這個問題。
# 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.
複制
11. Docker 預設使用網段
啟動的容器網絡無法互相通信,很是奇怪!
[問題起因] 我們在使用
Docker
啟動服務的時候,發現有時候服務之前可以互相連通,而有時間啟動的多個服務之前卻出現了無法通路的情況。究其原因,發現原來是因為使用的内部私有位址網段不一緻導緻的。有點服務啟動到了
172.17 - 172.31
的網段,有的服務跑到了
192.169.0 - 192.168.224
的網段,這樣導緻服務啟動之後出現無法通路的情況。
Docker預設使用網段
[解決方法] 上述問題的處理方式,就是手動指定
Docker
服務的啟動網段,就可以了。
# 檢視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": []
}
}
}
複制
12. Docker 服務啟動串台
使用 docker-compose 指令各自啟動兩組服務,發現服務會串台!
[問題起因] 在兩個不同名稱的目錄目錄下面,使用
docker-compose
來啟動服務,發現當
A
組服務啟動完畢之後,再啟動
B
組服務的時候,發現
A
組當中對應的一部分服務又重新啟動了一次,這就非常奇怪了!因為這個問題的存在會導緻,
A
組服務和
B
組服務無法同時啟動。之前還以為是工具的
Bug
,後來請教了“上峰”,才知道了原因,恍然大悟。
# 服務目錄結構如下所示
A: /data1/app/docker-compose.yml
B: /data2/app/docker-compose.yml
複制
[解決方法] 發現
A
和
B
兩組服務會串台的原因,原來是
docker-compose
會給啟動的容器加
label
标簽,然後根據這些
label
标簽來識别和判斷對應的容器服務是由誰啟動的、誰來管理的,等等。而這裡,我們需要關注的
label
變量是
com.docker.compose.project
,其對應的值是使用啟動配置檔案的目錄的最底層子目錄名稱,即上面的
app
就是對應的值。我們可以發現,
A
和
B
兩組服務對應的值都是
app
,是以啟動的時候被認為是同一個,這就出現了上述的問題。如果需要深入了解的話,可以去看對應源代碼。
Docker服務啟動串台
# 可以将目錄結構調整為如下所示
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
指令提供的參數
-p
來規避該問題的發生。
# 指定項目項目名稱
$ docker-compose -f ./docker-compose.yml -p app1 up -d
複制
13. Docker 指令調用報錯
在編寫腳本的時候常常會執行 docker 相關的指令,但是需要注意使用細節!
[問題起因]
CI
更新環境執行了一個腳本,但是腳本執行過程中報錯了,如下所示。通過對應的輸出資訊,可以看到提示說正在執行的裝置不是一個
tty
。
Docker指令調用報錯
随即,檢視了腳本發現報錯地方是執行了一個
exec
的
docker
指令,大緻如下所示。很奇怪的是,手動執行或直接調腳本的時候,怎麼都是沒有問題的,但是等到
CI
調用的時候怎麼都是有問題。後來好好看下下面這個指令,注意到
-it
這個參數了。
# 腳本調用docker指令
docker exec -it <container_name> psql -Upostgres ......
複制
我們可以一起看下
exec
指令的這兩個參數,自然就差不多了解了。
[解決方法]
docker exec
的參數
-t
是指
Allocate a pseudo-TTY
的意思,而
CI
在執行
job
的時候并不是在
TTY
終端中執行,是以
-t
這個參數會報錯。
Docker指令調用報錯
14. Docker 定時任務異常
在 Crontab 定時任務中也存在 Docker 指令執行異常的情況!
[問題起因] 今天發現了一個問題,就是在備份
Mysql
資料庫的時候,使用
docker
容器進行備份,然後使用
Crontab
定時任務來觸發備份。但是發現備份的
MySQL
資料庫居然是空的,但是手動執行對應指令切是好的,很奇怪。
# Crontab定時任務
0 */6 * * * \
docker exec -it <container_name> sh -c \
'exec mysqldump --all-databases -uroot -ppassword ......'
複制
[解決方法] 後來發現是因為執行的
docker
指令多個
-i
導緻的。因為
Crontab
指令執行的時候,并不是互動式的,是以需要把這個去掉才可以。總結就是,如果你需要回顯的話則需要
-t
選項,如果需要互動式會話則需要
-i
選項。
15. Docker 變量使用引号
compose 裡邊環境變量帶不帶引号的問題!
[問題起因] 使用過
compose
的同學可能都遇到過,我們在編寫啟動配置檔案的時候,添加環境變量的時候到底是使用單引号、雙引号還是不使用引号。時間長了,可能我們總是三者是一樣的,可以互相使用。但是,直到最後我們發現坑越來越多,越來越隐晦。
反正我是遇到過很多是因為添加引号導緻的服務啟動問題,後來得出的結論就是一律不适用引号。裸奔,體驗前所未有的爽快!
直到現在看到了 Github 中對應的 issus 之後,才終于破案了。
https://github.com/docker/compose/issues/2854
# TESTVAR="test"
在Compose中進行引用TESTVAR變量,無法找到
# TESTVAR=test
在Compose中進行引用TESTVAR變量,可以找到
# docker run -it --rm -e TESTVAR="test" test:latest
後來發現docker本身其實已經正确地處理了引号的使用
複制
[解決方法] 得到的結論就是,因為
Compose
解析
yaml
配置檔案,發現引号也進行了解釋包裝。這就導緻原本的
TESTVAR="test"
被解析成了
'TESTVAR="test"'
,是以我們在引用的時候就無法擷取到對應的值。現在解決方法就是,不管是我們直接在配置檔案添加環境變量或者使用
env_file
配置檔案,能不使用引号就不适用引号。
16. Docker 删除鏡像報錯
無法删除鏡像,歸根到底還是有地方用到了!
[問題起因] 清理服器磁盤空間的時候,删除某個鏡像的時候提示如下資訊。提示需要強制删除,但是發現及時執行了強制删除依舊沒有效果。
# 删除鏡像
$ docker rmi 3ccxxxx2e862
Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images
# 強制删除
$ dcoker rmi -f 3ccxxxx2e862
Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images
複制
[解決方法] 後來才發現,出現這個原因主要是因為
TAG
,即存在其他鏡像引用了這個鏡像。這裡我們可以使用如下指令檢視對應鏡像檔案的依賴關系,然後根據對應
TAG
來删除鏡像。
# 查詢依賴 - image_id表示鏡像名稱
$ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=<image_id>)
# 根據TAG删除鏡像
$ docker rmi -f c565xxxxc87f
# 删除懸空鏡像
$ docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
複制
17. Docker 普通使用者切換
切換 Docker 啟動使用者的話,還是需要注意下權限問題的!
[問題起因] 我們都知道在
Docker
容器裡面使用
root
使用者的話,是不安全的,很容易出現越權的安全問題,是以一般情況下,我們都會使用普通使用者來代替
root
進行服務的啟動和管理的。今天給一個服務切換使用者的時候,發現
Nginx
服務一直無法啟動,提示如下權限問題。因為對應的配置檔案也沒有配置
var
相關的目錄,無奈 ?♀ !️
# Nginx報錯資訊
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)
複制
[解決方法] 後來發現還是
nginx.conf
配置檔案,配置的有問題,需要将
Nginx
服務啟動時候需要的檔案都配置到一個無權限的目錄,即可解決。
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;
}
複制
文章作者: Escape
文章連結: https://escapelife.github.io/posts/43a2bb9b.html