天天看點

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

這裡主要是為了記錄在使用 Docker 的時候遇到的問題及其處了解決方法。
徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

Docker疑難雜症彙總

徹夜怒肝!17 個 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

指令單純複制檔案内容的話,就會出現屬性不一緻的情況,同時還會有一定的安全問題。

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

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

的網段,這樣導緻服務啟動之後出現無法通路的情況。

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

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

,是以啟動的時候被認為是同一個,這就出現了上述的問題。如果需要深入了解的話,可以去看對應源代碼。

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

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

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

Docker指令調用報錯

随即,檢視了腳本發現報錯地方是執行了一個

exec

docker

指令,大緻如下所示。很奇怪的是,手動執行或直接調腳本的時候,怎麼都是沒有問題的,但是等到

CI

調用的時候怎麼都是有問題。後來好好看下下面這個指令,注意到

-it

這個參數了。

# 腳本調用docker指令
docker exec -it <container_name> psql -Upostgres ......
           

複制

我們可以一起看下

exec

指令的這兩個參數,自然就差不多了解了。

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

[解決方法]

docker exec

的參數

-t

是指

Allocate a pseudo-TTY

的意思,而

CI

在執行

job

的時候并不是在

TTY

終端中執行,是以

-t

這個參數會報錯。

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

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

選項。

徹夜怒肝!17 個 Docker 常見疑難雜症解決方案彙總!

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