1Docker 遷移存儲目錄
默認情況系統會將 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服務 $sudosystemctlstopdocker #2.開始遷移目錄 $sudomv/var/lib/docker/data/ #3.添加軟鏈接 $sudoln-s/data/docker/var/lib/docker #4.啟動docker服務 $sudosystemctlstartdocker
[解決方法 2] 改動 docker 配置文件
#[方式一]改動docker啟動配置文件 $sudovim/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd--graph=/data/docker/
#[方式二]改動docker啟動配置文件 $sudovim/etc/docker/daemon.json { "live-restore":true, "graph":["/data/docker/"] }
[操作注意事項]在遷移docker目錄的時候注意使用的命令,要么使用mv命令直接移動,要么使用cp命令復制文件,但是需要注意同時復制文件權限和對應屬性,不然在使用的時候可能會存在權限問題。如果容器中,也是使用root用戶,則不會存在該問題,但是也是需要按照正確的操作來遷移目錄。
#使用mv命令 $sudomv/var/lib/docker/data/docker #使用cp命令 $sudocp-arv/data/docker/data2/docker
下圖中,就是因為啟動的容器使用的是普通用戶運行進程的,且在運行當中需要使用/tmp目錄,結果提示沒有權限。在我們導入容器鏡像的時候,其實是會將容器啟動時需要的各個目錄的權限和屬性都賦予了。如果我們直接是cp命令單純復制文件內容的話,就會出現屬性不一致的情況,同時還會有一定的安全問題。
Docker遷移存儲目錄
2Docker 設備空間不足
Increase Docker container size from default 10GB on rhel7.
[問題起因一]容器在導入或者啟動的時候,如果提示磁盤空間不足的,那么多半是真的因為物理磁盤空間真的有問題導致的。如下所示,我們可以看到/分區確實滿了。
#查看物理磁盤空間 $df-Th FilesystemSizeUsedAvailUse%Mountedon /dev/vda140G40G0G100%/ tmpfs7.8G07.8G0%/dev/shm /dev/vdb1493G289G179G62%/mnt
如果發現真的是物理磁盤空間滿了的話,就需要查看到底是什么占據了如此大的空間,導致因為容器沒有空間無法啟動。其中,docker自帶的命令就是一個很好的能夠幫助我們發現問題的工具。
#查看基本信息 #硬件驅動使用的是devicemapper,空間池為docker-252 #磁盤可用容量僅剩16.78MB,可用供我們使用 $dockerinfo Containers:1 Images:28 StorageDriver:devicemapper PoolName:docker-252:1-787932-pool PoolBlocksize:65.54kB BackingFilesystem:extfs Datafile:/dev/loop0 Metadatafile:/dev/loop1 DataSpaceUsed:1.225GB DataSpaceTotal:107.4GB DataSpaceAvailable:16.78MB MetadataSpaceUsed:2.073MB MetadataSpaceTotal:2.147GB
[解決方法]通過查看信息,我們知道正是因為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-161115,816INFOspawned:'app-demo'withpid835 2019-08-161116,268INFOexited:app(exitstatus1;notexpected) 2019-08-161117,270INFOgaveup:appenteredFATALstate,toomanystartretriestooquickly cp:cannotcreateregularfile'/etc/supervisor/conf.d/grpc-app-demo.conf':Nospaceleftondevice cp:cannotcreateregularfile'/etc/supervisor/conf.d/grpc-app-demo.conf':Nospaceleftondevice cp:cannotcreateregularfile'/etc/supervisor/conf.d/grpc-app-demo.conf':Nospaceleftondevice cp:cannotcreateregularfile'/etc/supervisor/conf.d/grpc-app-demo.conf':Nospaceleftondevice
[解決方法 1] 改動 docker 啟動配置文件
#/etc/docker/daemon.json { "live-restore":true, "storage-opt":["dm.basesize=20G"] }
[解決方法 2] 改動 systemctl 的 docker 啟動文件
#1.stopthedockerservice $sudosystemctlstopdocker #2.rmexisedcontainer $sudorm-rf/var/lib/docker #2.edityourdockerservicefile $sudovim/usr/lib/systemd/system/docker.service #3.findtheexecutionline ExecStart=/usr/bin/dockerd andchangeitto: ExecStart=/usr/bin/dockerd--storage-optdm.basesize=20G #4.startdockerserviceagain $sudosystemctlstartdocker #5.reloaddaemon $sudosystemctldaemon-reload
[問題起因三]還有一種情況也會讓容器無法啟動,并提示磁盤空間不足,但是使用命令查看發現并不是因為物理磁盤真的不足導致的。而是,因為對于分區的inode節點數滿了導致的。
#報錯信息 Nospaceleftondevice
[解決方法]因為ext3文件系統使用inode table存儲inode信息,而xfs文件系統使用B+ tree來進行存儲。考慮到性能問題,默認情況下這個B+ tree只會使用前1TB空間,當這1TB空間被寫滿后,就會導致無法寫入inode信息,報磁盤空間不足的錯誤。我們可以在mount時,指定inode64即可將這個B+ tree使用的空間擴展到整個文件系統。
Docker+K8s+Jenkins 主流技術全解視頻資料【干貨免費分享】
#查看系統的inode節點使用情況 $sudodf-i #嘗試重新掛載 $sudomount-oremount-onoatime,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節點。
#每個節點信息的內容 $statcheck_port_live.sh File:check_port_live.sh Size:225Blocks:8IOBlock:4096regularfile Device:822h/2082dInode:99621663Links:1 Access:(0755/-rwxr-xr-x)Uid:(1006/escape)Gid:(1006/escape) Access:2019-07-291459.498076903+0800 Modify:2019-07-291459.498076903+0800 Change:2019-07-292327.834866649+0800 Birth:- #磁盤的inode使用情況 $df-i FilesystemInodesIUsedIFreeIUse%Mountedon udev16478355801164775541%/dev tmpfs164876392521164851181%/run /dev/sdc224416256047884362393741242%/ tmpfs164876395164876341%/dev/shm
3Docker 缺共享鏈接庫
Docker 命令需要對/tmp 目錄下面有訪問權限
[問題起因]給系統安裝完compose之后,查看版本的時候,提示缺少一個名為libz.so.1的共享鏈接庫。第一反應就是,是不是系統少安裝那個軟件包導致的。隨即,搜索了一下,將相關的依賴包都給安裝了,卻還是提示同樣的問題。
#提示錯誤信息 $docker-compose--version errorwhileloadingsharedlibraries:libz.so.1:failedtomapsegmentfromsharedobject:Operationnotpermitted
[解決方法]后來發現,是因為系統中docker沒有對/tmp目錄的訪問權限導致,需要重新將其掛載一次,就可以解決了。
#重新掛載 $sudomount/tmp-oremount,exec
4Docker 容器文件損壞
對 dockerd 的配置有可能會影響到系統穩定
[問題起因]容器文件損壞,經常會導致容器無法操作。正常的docker命令已經無法操控這臺容器了,無法關閉、重啟、刪除。正巧,前天就需要這個的問題,主要的原因是因為重新對docker的默認容器進行了重新的分配限制導致的。
#操作容器遇到類似的錯誤 b'devicemapper:ErrorrunningdeviceCreate(CreateSnapDeviceRaw)dm_task_runfailed'
[解決方法]可以通過以下操作將容器刪除/重建。
#1.關閉docker $sudosystemctlstopdocker #2.刪除容器文件 $sudorm-rf/var/lib/docker/containers #3.重新整理容器元數據 $sudothin_check/var/lib/docker/devicemapper/devicemapper/metadata $sudothin_check--clear-needs-check-flag/var/lib/docker/devicemapper/devicemapper/metadata #4.重啟docker $sudosystemctlstartdocker
5Docker 容器優雅重啟
不停止服務器上面運行的容器,重啟 dockerd 服務是多么好的一件事
[問題起因]默認情況下,當Docker守護程序終止時,它會關閉正在運行的容器。從Docker-ce 1.12開始,可以在配置文件中添加live-restore參數,以便在守護程序變得不可用時容器保持運行。需要注意的是Windows平臺暫時還是不支持該參數的配置。
#Keepcontainersaliveduringdaemondowntime $sudovim/etc/docker/daemon.yaml { "live-restore":true } #在守護進程停機期間保持容器存活 $sudodockerd--live-restore #只能使用reload重載 #相當于發送SIGHUP信號量給dockerd守護進程 $sudosystemctlreloaddocker #但是對應網絡的設置需要restart才能生效 $sudosystemctlrestartdocker
[解決方法]可以通過以下操作將容器刪除/重建。
#/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 } ] }
$vim/etc/docker/daemon.json { "default-address-pools":[ { "base":"172.240.0.0/16", "size":24 } ] }
6Docker 容器無法刪除
找不到對應容器進程是最嚇人的
[問題起因]今天遇到docker容器無法停止/終止/刪除,以為這個容器可能又出現了dockerd守護進程托管的情況,但是通過ps -ef
#刪除容器 $sudodockerrm-ff8e8c3.. Errorresponsefromdaemon:Conflict,cannotremovethedefaultnameofthecontainer
[解決方法]找到/var/lib/docker/containers/下的對應容器的文件夾,將其刪除,然后重啟一下dockerd即可。我們會發現,之前無法刪除的容器沒有了。
#刪除容器文件 $sudorm-rf/var/lib/docker/containers/f8e8c3...65720 #重啟服務 $sudosystemctlrestartdocker.service
7Docker 容器中文異常
容器存在問題話,記得優先在官網查詢
[問題起因]今天登陸之前部署的MySQL數據庫查詢,發現使用SQL語句無法查詢中文字段,即使直接輸入中文都沒有辦法顯示。
#查看容器支持的字符集 root@b18f56aa1e15:#locale-a C C.UTF-8 POSIX
[解決方法]Docker部署的MySQL系統使用的是POSIX字符集。然而POSIX字符集是不支持中文的,而C.UTF-8是支持中文的只要把系統中的環境LANG改為"C.UTF-8"格式即可解決問題。同理,在K8S進入pod不能輸入中文也可用此方法解決。
#臨時解決 dockerexec-itsome-mysqlenvLANG=C.UTF-8/bin/bash
#永久解決 dockerrun--namesome-mysql -eMYSQL_ROOT_PASSWORD=my-secret-pw -dmysql:tag--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
8Docker 容器網絡互通
了解 Docker 的四種網絡模型
[問題起因]在本機部署Nginx容器想代理本機啟動的Python后端服務程序,但是對代碼服務如下的配置,結果訪問的時候一直提示502錯誤。
#啟動Nginx服務 $dockerrun-d-p80:80$PWD:/etc/nginxnginx
server{ ... location/api{ proxy_passhttp://localhost:8080 } ... }
[解決方法]后面發現是因為nginx.conf配置文件中的localhost配置的有問題,由于Nginx是在容器中運行,所以localhost為容器中的localhost,而非本機的localhost,所以導致無法訪問。
可以將nginx.conf中的localhost改為宿主機的IP地址,就可以解決502的錯誤。
#查詢宿主機IP地址=>172.17.0.1 $ipaddrshowdocker0 docker0:mtu1500qdiscnoqueuestateUPgroupdefault link/ether02d5f2:1ebrdffffff:ff inet172.17.0.1/16scopeglobaldocker0 valid_lftforeverpreferred_lftforever inet6fe80:d5fff21e/64scopelink valid_lftforeverpreferred_lftforever
server{ ... location/api{ proxy_passhttp://172.17.0.1:8080 } ... }
當容器使用host網絡時,容器與宿主共用網絡,這樣就能在容器中訪問宿主機網絡,那么容器的localhost就是宿主機的localhost了。
#服務的啟動方式有所改變(沒有映射出來端口) #因為本身與宿主機共用了網絡,宿主機暴露端口等同于容器中暴露端口 $dockerrun-d-p80:80--network=host$PWD:/etc/nginxnginxx
9Docker 容器總線錯誤
總線錯誤看到的時候還是挺嚇人了
[問題起因]在docker容器中運行程序的時候,提示bus error錯誤。
#總線報錯 $invapp.user_op--name=zhangsan Buserror(coredumped)
[解決方法]原因是在docker運行的時候,shm分區設置太小導致share memory不夠。不設置--shm-size參數時,docker給容器默認分配的shm大小為64M,導致程序啟動時不足。具體原因還是因為安裝pytorch包導致了,多進程跑任務的時候,docker容器分配的共享內存太小,導致torch要在tmpfs上面放模型數據用于子線程的 共享不足,就出現報錯了。
#問題原因 root@18...35:/opt/app#df-TH FilesystemTypeSizeUsedAvailUse%Mountedon overlayoverlay2.0T221G1.4T3%/ tmpfstmpfs68M068M0%/dev shmtmpfs68M41k68M1%/dev/shm #啟動docker的時候加上--shm-size參數(單位為b,k,m或g) $dockerrun-it--rm--shm-size=200mpytorch/pytorch:latest #在docker-compose添加對應配置 $shm_size:'2gb'
[解決方法]還有一種情況就是容器內的磁盤空間不足,也會導致bus error這樣的報錯,所以如果出現了,清除多余文件和目錄或者分配一個大的磁盤空間,就可以解決了。
#磁盤空間不足 $df-Th FilesystemTypeSizeUsedAvailUse%Mountedon overlayoverlay1T1T0G100%/ shmtmpfs64M24K64M1%/dev/shm
10Docker NFS 掛載報錯
NFS 掛載之后容器程序使用異常為內核版本太低導致的
[問題起因]我們將服務部署到openshift集群中,啟動服務調用資源文件的時候,報錯信息如下所示。從報錯信息中,得知是在Python3程序執行read_file()讀取文件的內容,給文件加鎖的時候報錯了。但是奇怪的是,本地調試的時候發現服務都是可以正常運行的,文件加鎖也是沒問題的。后來發現,在openshift集群中使用的是NFS掛載的共享磁盤。
#報錯信息 Traceback(mostrecentcalllast): ...... File"xxx/utils/storage.py",line34,inxxx.utils.storage.LocalStorage.read_file OSError:[Errno9]Badfiledescriptor
#文件加鎖代碼 ... withopen(self.mount(path),'rb')asfileobj: fcntl.flock(fileobj,fcntl.LOCK_EX) data=fileobj.read() returndata ...
[解決方法]從下面的信息得知,要在Linux中使用flock()的話,就需要升級內核版本到2.6.11+才行。后來才發現,這實際上是由RedHat內核中的一個錯誤引起的,并在kernel-3.10.0-693.18.1.el7版本中得到修復。所以對于NFSv3和NFSv4服務而已,就需要升級Linux內核版本才能夠解決這個問題。
#https://t.codebug.vip/questions-930901.htm $InLinuxkernelsupto2.6.11,flock()doesnotlockfilesoverNFS(i.e., thescopeoflockswaslimitedtothelocalsystem).[...]SinceLinux2.6.12, NFSclientssupportflock()locksbyemulatingthemasbyte-rangelocksontheentirefile.
11Docker 使用默認網段
啟動的容器網絡無法相互通信,很是奇怪!
[問題起因]我們在使用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":[] } } }
12Docker 服務啟動串臺
使用 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-papp1up-d
13Docker 命令調用報錯
在編寫腳本的時候常常會執行 docker 相關的命令,但是需要注意使用細節!
[問題起因]CI更新環境執行了一個腳本,但是腳本執行過程中報錯了,如下所示。通過對應的輸出信息,可以看到提示說正在執行的設備不是一個tty。
Docker命令調用報錯
隨即,查看了腳本發現報錯地方是執行了一個exec的docker命令,大致如下所示。很奇怪的是,手動執行或直接調腳本的時候,怎么都是沒有問題的,但是等到CI調用的時候怎么都是有問題。后來好好看下,下面這個命令,注意到-it這個參數了。
#腳本調用docker命令 dockerexec-itpsql-Upostgres......
我們可以一起看下exec命令的這兩個參數,自然就差不多理解了。
編號 | 參數 | 解釋說明 |
---|---|---|
1 | -i/-interactive | 即使沒有附加也保持 STDIN 打開;如果你需要執行命令則需要開啟這個選項 |
2 | -t/–tty | 分配一個偽終端進行執行;一個連接用戶的終端與容器 stdin 和 stdout 的橋梁 |
[解決方法]docker exec的參數-t是指Allocate a pseudo-TTY的意思,而CI在執行job的時候并不是在TTY終端中執行,所以-t這個參數會報錯。同時在 『stackoverflow』也有人給出原因,可以自行查看。
Docker命令調用報錯
14Docker 定時任務異常
在 Crontab 定時任務中也存在 Docker 命令執行異常的情況!
[問題起因]今天發現了一個問題,就是在備份Mysql數據庫的時候,使用docker容器進行備份,然后使用Crontab定時任務來觸發備份。但是發現備份的MySQL數據庫居然是空的,但是手動執行對應命令切是好的,很奇怪。
#Crontab定時任務 0*/6*** dockerexec-itsh-c 'execmysqldump--all-databases-uroot-ppassword......'
[解決方法]后來發現是因為執行的docker命令多個-i導致的。因為Crontab命令執行的時候,并不是交互式的,所以需要把這個去掉才可以。總結就是,如果你需要回顯的話則需要-t選項,如果需要交互式會話則需要-i選項。
編號 | 參數 | 解釋說明 |
---|---|---|
1 | -i/-interactive | 即使沒有附加也保持 STDIN 打開;如果你需要執行命令則需要開啟這個選項 |
2 | -t/–tty | 分配一個偽終端進行執行;一個連接用戶的終端與容器 stdin 和 stdout 的橋梁 |
15Docker 變量使用引號
compose 里邊環境變量帶不帶引號的問題!
[問題起因]使用過compose的朋友可能都遇到過,在編寫啟服務啟動配置文件的時候,添加環境變量時到底是使用單引號、雙引號還是不使用引號的問題?時間長了,我們可能會將三者混用,認為其效果是一樣的。但是后來,發現的坑越來越多,才發現其越來越隱晦。
反正我是遇到過很多問題,都是因為添加引號導致的服務啟動異常的,后來得出的結論就是一律不使引號。裸奔,體驗前所未有的爽快!直到現在看到了Github中對應的 issus 之后,才終于破案了。
#在Compose中進行引用TEST_VAR變量,無法找到 TEST_VAR="test" #在Compose中進行引用TEST_VAR變量,可以找到 TEST_VAR=test #后來發現docker本身其實已經正確地處理了引號的使用 dockerrun-it--rm-eTEST_VAR="test"test:latest
[解決方法]得到的結論就是,因為Compose解析yaml配置文件,發現引號也進行了解釋包裝。這就導致原本的TEST_VAR="test"被解析成了'TEST_VAR="test"',所以我們在引用的時候就無法獲取到對應的值。現在解決方法就是,不管是我們直接在配置文件添加環境變量或者使用env_file配置文件,能不使用引號就不適用引號。
需要注意的是環境變量配置的是日志格式的話(2022-01-01),如果使用的是Python的yaml.load模塊的話,會被當做是date類型的,這是如果希望保持原樣信息的話,可以使用'/"引起來將其變成字符串格式的。
16Docker 刪除鏡像報錯
無法刪除鏡像,歸根到底還是有地方用到了!
[問題起因]清理服器磁盤空間的時候,刪除某個鏡像的時候提示如下信息。提示需要強制刪除,但是發現及時執行了強制刪除依舊沒有效果。
#刪除鏡像 $dockerrmi3ccxxxx2e862 Errorresponsefromdaemon:conflict:unabletodelete3ccxxxx2e862(cannotbeforced)-imagehasdependentchildimages #強制刪除 $dcokerrmi-f3ccxxxx2e862 Errorresponsefromdaemon:conflict:unabletodelete3ccxxxx2e862(cannotbeforced)-imagehasdependentchildimages
[解決方法]后來才發現,出現這個原因主要是因為TAG,即存在其他鏡像引用了這個鏡像。這里我們可以使用如下命令查看對應鏡像文件的依賴關系,然后根據對應TAG來刪除鏡像。
#查詢依賴-image_id表示鏡像名稱 $dockerimageinspect--format='{{.RepoTags}}{{.Id}}{{.Parent}}'$(dockerimagels-q--filtersince=) #根據TAG刪除鏡像 $dockerrmi-fc565xxxxc87f
#刪除懸空鏡像 $dockerrmi$(dockerimages--filter"dangling=true"-q--no-trunc)
17Docker 普通用戶切換
切換 Docker 啟動用戶的話,還是需要注意下權限問題的!
[問題起因]我們知道在Docker容器里面使用root用戶的話,是不安全的,很容易出現越權的安全問題,所以一般情況下,我們都會使用普通用戶來代替root進行服務的啟動和管理的。今天給一個服務切換用戶的時候,發現Nginx服務一直無法啟動,提示如下權限問題。因為對應的配置文件也沒有配置var相關的目錄,無奈 ? !
#Nginx報錯信息 nginx:[alert]couldnotopenerrorlogfile:open()"/var/log/nginx/error.log"failed(13:Permissiondenied) 2020/11/121547[emerg]23#23:mkdir()"/var/cache/nginx/client_temp"failed(13:Permissiondenied)
[解決方法]后來發現還是nginx.conf配置文件,配置的有問題,需要將Nginx服務啟動時候需要的文件都配置到一個無權限的目錄,即可解決。
userwww-data; worker_processes1; error_log/data/logs/master_error.logwarn; pid/dev/shm/nginx.pid; events{ worker_connections1024; } http{ include/etc/nginx/mime.types; default_typeapplication/octet-stream; gzipon; sendfileon; tcp_nopushon; keepalive_timeout65; 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; }
18Docker 綁定到 IPv6 上
Docker 服務在啟動的時候,將地址綁定到 IPv6 地址上面了,提示報錯信息!
[問題起因]物理機器更新了對應補丁之后,重啟了服務,導致原本可以正常啟動的docker-compose服務提示如下報錯信息。不清楚是否修改了操作系統的相關配置,還是對應docker進行的其他方面的配置,比如修改/etc/docker/daemon.json或者docker的service啟動文件。
#Docker的報錯信息 dockerrun-p80:80nginx:alpinesucceeds.Previously,thiswasfailingwithError startinguserlandproxy:listentcp6[::]socket:addressfamilynotsupportedbyprotocol.
[解決方法]通過如上所示的報錯信息,可以看到服務的啟動端口綁定到了tcp6上面了,但是對應的socket發現系統本身并不支持。這時,我們一看下對應的操作系統ipv6的設置,發現系統禁用了,所有的ipv6地址。需要了解的朋友,可以參考 fix port forwarding with ipv6.disable=1 和 cannot start if ipv6 is disabled on host 這兩個issus來獲取更多信息。
#操作系統配置 $cat/etc/sysctl.conf|grepipv6 net.ipv6.conf.all.disable_ipv6=1
[方法一]最為簡單的解決方法,就是在docker-compose.yml文件中,手動指定將對應服務的端口綁定到ipv4上面,如下所示。
version:"3" services: app: restart:on-failure container_name:app_web image:app:latest ports: -"0.0.0.080/tcp" volumes: -"./app_web:/data" networks: -app_network networks: app_network:
[方法二]或者修改/etc/docker/daemon.json文件,在配置中,阻止Docker錯誤的將端口映射到IPv6上,即可達到同樣的效果,且不用再次修改多個服務的啟動配置文件了。
#修改配置 $vim/etc/docker/daemon.json { "ipv6":false, "fixed-cidr-v6":"20011::/64" } #重啟服務 $systemctlreloaddocker
[方法三]Docker默認情況下會同時將端口映射于IPv4與IPv6兩者上,而且有的時候會出現只綁定到了IPv6,導致服務無法正常訪問的情況。現在通用的始終還是IPv4地址,因此最簡單的做法就是關閉IPv6地址。詳細的配置,可以參考 Port redirecting binding to IPv6 but not IPv4 interfaces 這個issus地址。
#修改系統配置 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 #重啟網絡 $/etc/init.d/networkingrestart #最后檢測是否已關閉IPv6 ipaddrshow|grepnet6
1919. Docker 容器啟動超時
Docker 服務在啟動的時候,提示超時,被直接終止了!
[問題起因]使用docker-compose啟動容器的時候,等待了很久的時候(大約2-3分鐘左右),之后提示如下信息。通過閱讀信息內容,可以看到是因為超時導致的,提示可以通過設置環境變量,加大超時的時間。
$docker-composeup-d ERROR:forxxxUnixHTTPConnectionPool(host='localhost',port=None):Readtimedout.(readtimeout=70) ERROR:AnHTTPrequesttooktoolongtocomplete.Retrywith--verbosetoobtaindebuginformation. Ifyouencounterthisissueregularlybecauseofslownetworkconditions,considersettingCOMPOSE_HTTP_TIMEOUTtoahighervalue(currentvalue:60).
[解決方法]按照提示設置的環境變量之后,再次啟動發現確實可以正常啟動了,但是還是能夠感覺到有些慢。
$sudovim/etc/profile exportCOMPOSE_HTTP_TIMEOUT=500 exportDOCKER_CLIENT_TIMEOUT=500
排除了下啟動流程,因為容器啟動有映射目錄到容器里面且目錄大小比較大,所以懷疑是因為i/o導致的。隨即使用iotop命令查看服務器目前的i/o情況,發現存在很多個rg命令,且都處于100%左右。查了下,發現是vscode遠程服務器啟動的搜索目錄結構的進程,西八,有些坑呀!
$sudoiotop 4269be/4escape15.64K/s0.00B/s0.00%98.36%rg--files--hidden 4270be/4escape28.15K/s0.00B/s0.00%97.46%rg--files--hidden 4272be/4escape31.27K/s0.00B/s0.00%97.39%rg--files--hidden 4276be/4escape34.40K/s0.00B/s0.00%96.98%rg--files--hidden
20Docker 端口網絡限制
如果發現服務都一切正常,但是無法無法訪問的話,則多為網絡問題!
[問題起因]啟用服務之后,登錄跳轉發現直接502報錯了。排除了配置等相關原因都沒有任何問題(做過相關測試),這就非常奇怪了!
#部署服務架構 nginx(80)->web1(8080) ->web2(8081) #報錯信息如下所示 nginxconnect()failed(113:Noroutetohost)whileconnectingtoupstream
[解決方法]根據錯誤信息可知,是因為沒有路由到指定的host導致了,隨即看了下防火墻是開著的,看了日志發現被過濾掉了,西八!問題找到了,現在需要做的就是,要么添加防火墻規則,要么關閉防火墻。
#檢查開放的端口 $sudofirewall-cmd--permanent--zone=public--list-ports #開啟需要路由的端口 $sudofirewall-cmd--permanent--zone=public--add-port=8080/tcp $sudofirewall-cmd--permanent--zone=public--add-port=8081/tcp #配置立即生效 firewall-cmd--reload
#關閉防火墻 $sudosystemctlstopfirewalld.service #禁用自啟動 $sudosystemctldisablefirewalld.service
21Docker 無法獲取鏡像
新初始化的機器,無法獲取私有倉庫的鏡像文件!
[問題起因]機器初始化之后,使用如下命令登錄私有docker倉庫,發現提示無法獲取對應鏡像,但是在其他機器上面獲取該鏡像就可以執行成功,這就非常奇怪了!
#登錄私有倉庫 $echo'123456'|dockerlogin-uescape--password-stdindocker.escapelife.site #異常信息提示 $sudodockerpulldocker.escapelife.site/app:0.10 Errorresponsefromdaemon:manifestfordocker.escapelife.site/app:0.10notfound:manifestunknown:manifestunknown
[解決方法]太坑了,我還以為我發現某個隱藏的bug了,可勁的排查,最后發現,原來是自己鏡像包名字寫錯了,應該寫成0.0.10的,自己卻寫成了0.10。這里,紀念一下,以后碰到上述報錯,那肯定是鏡像不存在的。
#登錄私有倉庫之后會在用戶家目錄下生成一個docker配置 #其用來記錄docker私有倉庫的登錄認證信息(是加密過的信息但不安全)=>base64 $cat.docker/config.json { "auths":{ "docker.escapelife.site":{ "auth":"d00u11Fu22B3355VG2xasE12w==" } } }
22Docker 使容器不退出
如何使使用 docker-compose 啟動的容器服務 hang 住而不退出
[問題起因]有時候我們啟動的服務,因為某些問題(bug)導致服務無法正常啟動,就會出現容器無限重啟(restart: on-failure)的情況,這時就很不利于排除問題。
?dockerps-a 4e6xxx9a4app:latest"/xxx/…"26secondsagoRestarting(1)2secondsago
[解決方法]這時我們就需要根據,服務構建使用命令來決定是用什么命令來hang住服務。卡住的原理,就類似于使用/bin/bash進入容器是一樣的,這里我就不過多解釋了。
#類似原理 dockerrun-it--rm--entrypoint=/bin/bashxxx/app:latest #使用Command命令 tty:true command:tail-f/dev/null #使用Entrypoint命令 tty:true entrypoint:tail-f/dev/null
同理,我們在使用docker-compose或者k8s平臺部署服務的時候,也有時會因為啟動問題需要,使啟動的服務不直接退出,來手動調試和排查問題原因。所以,我這里記錄下其不同部署方式的,暫停方式。
#Compose version:"3" services: app: image:ubuntu:latest tty:true entrypoint:/usr/bin/tail command:"-f/dev/null"
#K8S apiVersion:v1 kind:Pod metadata: name:ubuntu spec: containers: -name:ubuntu image:ubuntu:latest command:["/bin/bash","-c","--"] args:["whiletrue;dosleep30;done;"] #command:["sleep"] #args:["infinity"]
23Docker 不使用默認網段
有些情況,內部規劃的網段和可能和 Dockerd 默認的網段有沖突,導致異常出現!
[問題起因]今天在新機器上面,部署了一整套服務(多臺機器),服務部署完畢之后,通過前置Nginx服務發現并不能訪問,后置機器開放的端口,發現發到對應端口的請求都沒有轉發出去。這就比較奇怪了,因為端口控制是已經開通了的,不應該出現不通的情況。
?nc-v172.16.100.128000 nc:connectto172.16.100.12port8000(tcp)failed:Connectionrefused
[解決方法]發現服務器端口不通,我這里懷疑可能是dockerd服務啟動導致的,所以我先將服務都停掉,直接在機器上面啟動了Python的服務端程序(Linux機器自帶Python2.7.x的版本),然后在前置Nginx服務發現,端口確實是通的。后來,排除發現是內部服務默認網段和dockerd服務啟動的默認網段是沖突的,導致重寫了機器的防火墻規則,導致出現上述異常的。
$python-mSimpleHTTPServer8000 ServingHTTPon0.0.0.0port8000... ?nc-v172.16.100.128000 Connectionto172.16.100.128000port[tcp/*]succeeded!
既然問題已經知道了,現在需要做的就是非常簡單了:不適用默認網段!通過 『mirantis』 里面,我們可以選擇進行設置,然后重啟服務dockerd服務,即可。
#修改配置 $sudocat/etc/docker/daemon.json { "default-address-pools":[{"base":"192.168.100.0/20","size":24}] } #重啟服務 $sudosystemctlrestartdocker #啟動服務驗證是否生效 $ipa $dockernetworkinspectapp|grepSubnet
這時,就到了考驗我們網絡的子網劃分的能力了:如何在給定的網段下面合理且高效的進行劃分呢?咳咳,確實難倒我了,這時我們可以再這個在線網站上面 JSON 在線解析 進行劃分,然后選定合理的base和size就可以了。
#報錯信息 Errorresponsefromdaemon:couldnotfindanavailable,non-overlappingIPv4addresspoolamongthedefaultstoassigntothenetwork #按照下圖我們可以對pool進行合理劃分 #給定10.210.200.0+255.255.255.0的網段來劃分子網 $sudocat/etc/docker/daemon.json { "default-address-pools":[{"base":"10.210.200.0/24","size":28}] }
其中,base告訴我們劃分子網的網段是什么(從來開始),是從前兩位(/16)開始,還是第三位開始(/24)呢?而size則告訴我們劃分的每個子網有多少IP地址可以使用呢?從"10.210.200.0/24"我們可以知道,該網絡下面只有254個可用的IP地址(直接使用肯定不夠),然后我們需要給docker使用,劃分每個子網可用16個IP地址,所以子網就應該寫成28了。
Docker 不使用默認網段
24Docker 添加私有倉庫
有些情況,我們服務器上面需要使用內部私有的容器鏡像地址!
[問題起因]如果新機器上面需要使用私有倉庫的話,但是又沒有配置,再獲取鏡像的時候就會出現如下報錯信息。
#拉取/登陸私庫時提示 $dockerpull192.168.31.191:5000/nginx:latest x509:certificatesignedbyunknownauthority
[解決方法]該問題的處理方式很簡單,如下所示,配置一下倉庫地址,重啟服務并登陸私有倉庫就可以了。
#添加配置 $sudocat/etc/docker/daemon.json { "insecure-registries":["192.168.31.191:5000"] } #重啟docker $sudosystemctlrestartdocker #重新登錄即可 $dockerlogin私庫地址-u用戶名-p密碼
原文標題:24 個 Docker 常見問題處理技巧
文章出處:【微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
-
存儲
+關注
關注
13文章
4261瀏覽量
85669 -
服務器
+關注
關注
12文章
9017瀏覽量
85182 -
Docker
+關注
關注
0文章
454瀏覽量
11814
原文標題:24 個 Docker 常見問題處理技巧
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論