Docker 是一個開源的容器引擎,可以輕鬆的為任何應用建立一個輕量級的、可移植的、自給自足的容器。開發者和系統管理員在筆電上編譯測試通過的容器可以批次地在生產環境中部署,包括 VMs(虛擬機器器)、bare metal、OpenStack 叢集、雲端、資料中心和其他的基礎應用平臺。容器是完全使用沙箱機制,相互之間不會有任何介面。
為啥要用Docker?這要從目前軟體行業的痛點來講起
有了Docker可以很大程度解決上面的問題。
首先,Docker的使用簡單至極,從開發的角度來看就是三步走:構建,運輸,執行。其中關鍵步驟就是構建環節,即打包映象檔案。但是從測試和運維的角度來看,那就只有兩步:複製,執行。有了這個映象,那麼想複製到哪執行都可以,完全和平臺無關了。同時Docker這種容器技術隔離出了獨立的執行空間,不會和其他應用爭用系統資源了以及還不需要考慮應用之間相互影響,想想就開心。
其次,因為在構建映象的時候就處理完了服務程式對於系統的所有依賴,所以在你使用的時候,你可以忽略掉原本程式的依賴以及開發語言。對測試和運維而言,更多專注於自己的業務內容上。
最後,Docker於開發者而言提供了一種開發環境的管理辦法,與測試人員而言保證了環境的同步,於運維人員提供了可移植的標準化部署流程。
你需要在本地系統快速嘗試 Magento,或者為一個專案使用 MySQL?還是希望嘗試大部分開源專案?那就使用 Docker 吧,它將幫你節省大量時間。Docker 能提升開發者的開發效率,讓我們快速搭建開發環境。
開發環境的機器通常記憶體比較小,此前使用虛擬的時候,經常需要為開發環境的機器加記憶體,而通過 Docker 可以輕易的讓幾十個服務在 Docker 中跑起來。
如果你希望構建原始碼,但發現沒有準備好合適的環境。
那麼使用 Docker是一個值得考慮的方案。畢竟如果使用傳統的方法一個一個地安裝軟體,一大堆軟體安裝下來確實十分費時間,使用容器技術省時省力,何樂而不為?它能讓你將執行環境和設定放在程式碼中然後部署,同一個 Docker 的設定可以在不同的環境中使用,這樣就降低了硬體要求和應用環境之間耦合度。這裡有一個值得一看的例子: docker golang builder。
你在使用微服務嗎?微服務架構將一個整體式的應用拆分成鬆耦合的單個服務。
那不妨考慮一下 Docker,你可以將每個服務打包為一個docker映象並使用docker-compose 來模擬生產環境(checkout docker networks)。最開始實踐的時候可能會比較費時費力,但長遠地來看,最終將產生巨大的生產力。
試想這樣一個問題,如何編寫自動化的整合測試用例,這些測試用例無需花很長時間來開始執行,使用者也可輕鬆管理。這裡不是指在 Docker 中執行測試用例,而是將測試用例與映象緊密執行在一起。當你針對一個 docker 映象編寫測試用例時會有一個很大的優勢。下面簡單介紹一下我的測試流程:執行兩個 docker 映象(app + db),在 MySQL 啟動時載入資料,並在 app docker 上使用 API。可檢視此指令碼以獲取快速的範例。
你可以使用 docker 映象進行自我部署。許多主流的主機提供商都支援託管 docker,如果你擁有一個具有 shell 存取許可權的專用節點/vm,那麼事情將變得更容易。只需要設定好docker,並在你想要的埠上執行你的映象即可。
都說 Docker 天生適合持續整合/持續部署,在部署中使用Docker,持續部署將變得非常簡單,並會在進入新的映象後重新開始。關於這個部分的自動化工作,現在已經有許多方案以供選擇,Kubernetes就是一個耳熟能詳的名字。Kubernetes是容器叢集管理系統,是一個開源的平臺,可以實現容器叢集的自動化部署、自動擴縮容、維護等功能。
Docker 有意思的一個使用場景是在多租戶的應用中,它可以避免關鍵應用的重寫。如果你將應用程式服務公開給多個租戶(租戶指一組使用者,例如組織),使用單租戶方案設計的應用程式如果用上了 sub-domain + docker 可以快速獲得提供多租戶的服務。
關於這個場景的一個例子是為物聯網的應用開發一個快速、易用的多租戶環境。這種多租戶的基本程式碼非常複雜,很難處理,重新規劃這樣一個應用不但消耗時間,也浪費金錢。使用Docker,可以為每一個租戶的應用層的多個範例建立隔離的環境,這不僅簡單而且成本低廉,當然這一切得益於 Docker 環境的啟動速度和其高效的 diff 命令。
這與上面提到的微服務有些聯絡,但即使你沒有使用微服務,只是提供服務,Docker仍可以很好地管理單個機器上的所有服務。你應該使用資料夾掛載來為每個基於資料的 docker 映象保留資料。
Docker 通過建立另一個容器來幫助你輕鬆地進行水平擴充套件。如果遇到巨大的高峰流量,Docker可以幫助你解決問題 —— 只需新增更多的機器並增加負載均衡器背後執行的容器數量。
想全面瞭解的朋友可以參考:太全了|萬字詳解Docker架構原理、功能及使用
root@centos7 ~]# yum install docker -y
[root@centos7 ~]# systemctl start docker
下載映象檔案
[root@centos7 ~]# docker pull centos:latest
Trying to pull repository docker.io/library/centos ...
centos7: Pulling from docker.io/library/centos
93857f76ae30: Pull complete
Digest: sha256:4eda692c08e0a065ae91d74e82fff4af3da307b4341ad61fa61771cc4659af60
[root@centos7 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos centos7 a8493f5f50ff 3 days ago 192.5 MB
刪除映象
[root@centos7 ~]# docker rmi a8493f5f50ff ##容器ID
方法一:
[root@centos7 ~]# docker run centos /bin/echo "nihao" ##建立容器
nihao
[root@centos7 ~]# docker ps -a ##檢視所有容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c113f9a4f1b centos "/bin/echo nihao" 43 seconds ago Exited (0) 41 seconds ago boring_liskov
這裡沒有指定容器名稱,自動命名,狀態是自動退出
方法二:建立一個自定義名稱的容器
[root@centos7 ~]# docker run --name mgg -t -i centos /bin/bash
名稱 分配偽終端 -i 處於開啟狀態
[root@2db7f1389dbd /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 22:46 ? 00:00:00 /bin/bash
root 13 1 0 22:49 ? 00:00:00 ps -ef
[root@centos7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 4 minutes ago Up 4 minutes mgg
docker ps -a是顯示所有容器包括沒有執行的(同virsh list --all)
[root@2db7f1389dbd /]# exit ##退出容器
exit
[root@centos7 ~]# docker start 2db7f1389dbd ##啟動容器
2db7f1389dbd
[root@centos7 ~]# docker attach 2db7f1389dbd ##進入容器(必須是啟動狀態下)
[root@2db7f1389dbd /]# hostname
2db7f1389dbd
這種進入方式,退出後容器就進入Down狀態,如下
[root@2db7f1389dbd /]# exit
exit
[root@centos7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@centos7 ~]# nsenter --help
Usage:
nsenter [options] <program> [<argument>...]
Run a program with namespaces of other processes.
Options:
-t, --target <pid> target process to get namespaces from
-m, --mount[=<file>] enter mount namespace
-u, --uts[=<file>] enter UTS namespace (hostname etc)
-i, --ipc[=<file>] enter System V IPC namespace
-n, --net[=<file>] enter network namespace
-p, --pid[=<file>] enter pid namespace
-U, --user[=<file>] enter user namespace
-S, --setuid <uid> set uid in entered namespace
-G, --setgid <gid> set gid in entered namespace
--preserve-credentials do not touch uids or gids
-r, --root[=<dir>] set the root directory
-w, --wd[=<dir>] set the working directory
-F, --no-fork do not fork before exec'ing <program>
-Z, --follow-context set SELinux context according to --target PID
-h, --help display this help and exit
-V, --version output version information and exit
獲取容器的PID
[root@centos7 ~]# docker inspect --format "{{.State.Pid}}" 2db7f1389dbd
4580
[root@centos7 ~]# nsenter -t 4580 -u -i -n -p
[root@2db7f1389dbd ~]# hostname
2db7f1389dbd
[root@2db7f1389dbd ~]# exit
logout
[root@centos7 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 22 minutes ago Up 7 minutes mgg
[root@centos7 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 31 minutes ago Up 16 minutes mgg
3c113f9a4f1b centos "/bin/echo nihao" 38 minutes ago Exited (0) 38 minutes ago boring_liskov
[root@centos7 ~]# docker rm 3c113f9a4f1b ##接名稱也可以,刪除一個停止的容器
3c113f9a4f1b
[root@centos7 ~]# docker rm -f 3c113f9a4f1b ##刪除一個正在執行的容器
[root@centos7 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2db7f1389dbd centos "/bin/bash" 31 minutes ago Up 16 minutes mgg
[root@centos7 ~]# docker run --rm centos /bin/echo "hello" ##建立時自動刪除,用於測試
[root@centos7 ~]#docker --kill $(docker ps -a -q) ##刪除正在執行的容器
Dokcer 通過使用 Linux 橋接提供容器之間的通訊,Docker的網路模式有四種
分別是以下四種模式:
如果容器使用 host 模式,那麼容器將不會獲得一個獨立的 Network Namespace,而是和宿主機共用一個 Network Namespace。容器將不會虛擬出自己的網路卡與設定 IP 等,而是使用宿主機的 IP 和埠。就和直接跑在宿主機中一樣。但是容器的檔案系統、程序列表等還是和宿主機隔離的。
這個模式指定新建立的容器和已經存在的一個容器共用一個 Network Namespace,而不是和宿主機共用。新建立的容器不會建立自己的網路卡與設定 IP,而是和一個指定的容器共用 IP、埠範圍等。同樣,兩個容器除了網路方面,其他方面仍然是隔離的。
此模式不同於前兩種,Docker 容器有自己的 Network Namespace,但是,Docker容器沒有任何網路設定。而是需要我們手動給 Docker容器新增網路卡、設定 IP 等。
此模式是Docker預設的網路設定,此模式會為每一個容器分配Network Namespace,並將一個主機上的Docker容器連線到一個虛擬網橋上。
更多關於Docker容器網路介紹請參考:Docker容器網路-基礎篇,Docker容器網路-實現篇。
docker管理資料的方式有兩種:
預設容器的資料是儲存在容器的可讀寫層,當容器被刪除時其上的資料也會丟失,所以為了實現資料的永續性則需要選擇一種資料持久技術來儲存資料。官方提供了三種儲存方式:Volumes、Bind mounts和tmpfs。
從現在開始,我們學習 Docker 容器的資料儲存方式,你也可以先了解一下Docker 資料持久化的三種方案。
Bind mount 會覆蓋容器中的檔案,而 volume mount 則不會。即如果容器中已有檔案,則會將檔案同步到主機的目錄上。此方式與 Linux 系統的 mount 方式很相似,即是會覆蓋容器內已存在的目錄或檔案,但並不會改變容器內原有的檔案,當 umount 後容器內原有的檔案就會還原。
由docker建立和管理,且與主機的核心功能隔離
允許容器將內容儲存到遠端、雲服務提供商、加密內容等等
資料卷是儲存在 Docker 容器的特定目錄下面
Docker Volumes 機制通常用來給 Docker 容器儲存持久化資料,使用 Volumes 有很多優勢:
Volumes 通常也優於容器的可寫層,使用 Volumes 不會增加容器的體積,並且 Volumes 的內容儲存在外部獨立於容器的生命週期。如果容器不產生持久化資料,可以考慮使用 tmpfs 記憶體對映(只儲存在容器的記憶體中)的方式來避免資料儲存在其他可能的地方,避免增加容器的體積。
最開始的時候 -v 或者 --volume 選項是給單獨容器使用,而 --mount 選項是給叢集服務使用。但是從 Docker 17.06 開始,也可以在單獨容器上使用 --mount。通常來講 --mount 選項也更加具體和詳細。-v 選項將所有選項集中到一個值,而 --mount 選項將可選項分開。如果需要指定 volume driver 選項,那麼必須使用 --mount 選項。
# 建立一個資料卷
$ docker volume create my-vol
# 檢視所有的資料卷
$ docker volume ls
# 檢視指定資料卷的資訊
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
# 移除指定資料卷的
$ docker volume rm my-vol
# 清除無主的資料卷
$ docker volume prune
# 啟動一個掛載資料卷的容器
$ docker run -d -P --name web \
-v my-vol:/wepapp \
training/webapp python app.py
$ docker run -d -P --name web \
--mount source=my-vol,target=/webapp \
training/webapp python app.py
# 啟動一個掛載資料卷的服務
$ docker service create -d --name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest
# 掛載為唯讀模式
$ docker run -d --name=nginxtest \
-v nginx-vol:/usr/share/nginx/html:ro \
nginx:latest
# type可以分為bind、volume、tmpfs, 預設為volume
# source用於設定資料卷的名稱,匿名資料卷可以省略
# target表示需要掛載到容器裡面的地方
# readonly表示掛載的內容為唯讀模式,可選
# volume-opt表示可以使用多次,可選
$ docker run -d --name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
[3] 掛載遠端資料卷
# 外掛sshfs允許您輕鬆地在容器中掛載遠端資料夾
# 下載該外掛
$ docker plugin install --grant-all-permissions vieux/sshfs
# 使用該驅動建立ssh資料卷
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
-o port=3336 \
sshvolume
# 啟動該驅動程式建立卷建立容器
# 如果兩個容器設定了可信關係,就不需要設定volume-opt密碼了
$ docker run -d \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume,target=/app, \
volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest
掛載主機目錄是將主機中的特定目錄直接掛在到容器內部使用
# 使用bind模式啟動容器
$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app \
nginx:latest
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest
# 看下對應的資訊
$ docker inspect devtest
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
# 掛載為唯讀模式
$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app:ro \
nginx:latest
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app,readonly \
nginx:latest
$ docker run -d -it --name devtest \
-v "$(pwd)"/target:/app \
-v "$(pwd)"/target:/app2:ro,rslave \
nginx:latest
$ docker run -d -it --name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
--mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
nginx:latest
記憶體對映是將記憶體對映到容器內供容器內部使用
最開始 --tmpfs 是給單獨容器使用,而 --mount 選項是給 swarm 叢集服務使用的。但是,從 Docker 17.06 開始,也可以在單獨容器上使用 --mount 了。通常說來,--mount 更明確,更冗長。最大的區別是 --tmpfs 標誌不支援任何可設定選項。其中 --tmpfs 只能在容器中使用,而 swarm 叢集則必須使用 --mount 來使用 tmpfs 記憶體對映。
# 容器上使用
$ docker run -d -it --name tmptest \
--tmpfs /app \
nginx:latest
$ docker run -d -it --name tmptest \
--mount type=tmpfs,destination=/app \
nginx:latest
在容器外部檢視容器內部的紀錄檔輸出情況,便於排除和監控問題
可以利用 docker logs 命令,檢視 Docker 容器內部應用程式執行時所產生的紀錄檔。可以免除首先進入 Docker 容器,再開啟應用程式的紀錄檔檔案的過程。docker logs 會監控容器中作業系統的標準輸出裝置(STDOUT),一旦 STDOUT 有資料產生,就會將這些資料傳輸到另一個裝置中,則被稱為紀錄檔驅動(Logging Driver)。
# 動態檢視紀錄檔內容
$ docker logs -f netdata
Docker 是怎樣做到的呢?我們使用 docker info 命令,可以看到 Docker 容器的相關資訊,其中有一項 Logging Driver 的欄位。
# 當前所設定的紀錄檔驅動型別
$ docker info | grep 'Logging Driver'
Logging Driver: json-file
我們可以在 docker run 命令中通過 --log-driver 引數來設定具體的 Docker 紀錄檔驅動,也可以通過 --log-opt 引數來指定對應紀錄檔驅動的相關選項。
docker run -d -p 80:80 --name nginx \
--log-driver json-file \ # 設定紀錄檔驅動
--log-opt max-size=10m \ # 表示JSON檔案最大為10MB,超過則生成新的檔案
--log-opt max-file=3 \ # 表示JSON檔案最多儲存3個,超過則刪除多餘檔案
nginx
# 當然,可以在組態檔中新增,全域性生效
$ cat /etc/docker/daemon.json
{
"log-driver": "syslog"
}
# 修改設定之後重新啟動服務
$ sudo systemctl restart docker
額外,需要注意的是,預設情況下,Docker 將紀錄檔儲存到一個紀錄檔檔案。
# 檢查紀錄檔檔案路徑
$ docker inspect --format='{{.LogPath}}' netdata
/var/lib/docker/containers/556553bcb5xxx13cbc588a4-json.log
# 檢視實時紀錄檔資訊
$ tail -f `docker inspect --format='{{.LogPath}}' netdata`
上述內容參考: https://escapelife.github.io/...
安裝完成docker容器服務之後,需要了解如何操作它?在shell命令列下直接輸入docker就可以檢視幫助資訊,如下。
[root@master ~]# docker
Usage: docker COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/root/.docker")
-D, --debug Enable debug mode
--help Print usage
-H, --host list Daemon socket(s) to connect to (default [])
-l, --log-level string Set the logging level ("debug", "info", "warn", "error", "fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
container Manage containers
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
volume Manage volumes
Commands:
attach Attach to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
命令很多,重點介紹這20個,請詳細閱讀下面的文章:
Docker可以使用Dockerfile的內容來自動構建映象。Dockerfile也是一個檔案,其中有建立映象、執行指令等一系列的命令,且每行只支援一個執行命令。
Docker file分為四部分組成:
dockerfile指令忽略大小寫,建議大寫,#作為註釋,每行只支援一條指令,指令可以帶多個引數。
dockerfile指令有:
Dockerfile指令一共有以下種:
用來指定基礎映象,然後通過在基礎映象上構建新的映象,基礎映象一般有遠端或本地倉庫。並且Dockerfile檔案第一行必須的FROM指令,如果一個Dockerfile需要建立多個映象,可以使用多個FROM指令。
#具體使用用法如下:
FROM < image_name > #預設是latest版本
FROM <image:version> #指定版本
指定映象的建立者資訊
#具體使用法如下:
MAINTAINER < name >
執行所有基礎映象能支援的命令,同樣也可以使用多條RUN指令,可以使用\來換行
#具體使用法如下:
RUN < command >
RUN ["executable", "param1", "param2" ... ] (exec form)
用於容器啟動時的指定操作,它可以是命令,也可以是指令碼,但只執行一次,如果有多少預設只會執行最後一個。
#具體使用法如下:
CMD [「executable」 ,」Param1」, 「param2」]使用exec執行,推薦
CMD command param1 param2,在/bin/sh上執行
CMD [「Param1」, 「param2」] 提供給ENTRYPOINT做預設引數。
指定容器的埠對映(容器與物理機),執行容器時加上-p引數指定EXPOSE設定的埠。EXPOSE可以設定多個埠號,相應地執行容器配套多次使用-p引數。可以通過docker port +容器需要對映的埠號和容器ID來參考宿主機的對映埠。
#具體使用法如下:
EXPOSE <port> [port1 , port2 ............]
在映象中用於設定環境變數的,然後RUN命令可以使用此設定的環境變數,在容器啟動後也以通過docker inspect檢視環境變數,可以通過docker run --env key=value來設定或修改環境變數。
#具體使用法如下:
ENV <key> <value>
ENV JAVA_HOME /usr/local/jdk
複製指定的原始檔、目錄、URL到容器的指定目錄中。所有拷貝到container中的檔案和資料夾許可權為0755,uid和gid為0。
如果源是一個目錄,那麼會將該目錄下的所有檔案新增到container中,不包括目錄;
如果原始檔是可識別的壓縮格式,則docker會幫忙解壓縮(注意壓縮格式);
如果源是檔案且目標目錄中不使用斜槓結束,則會將目標目錄視為檔案,源的內容會寫入目標目錄;
如果源是檔案且目標目錄中使用斜槓結束,則會原始檔拷貝到目標目錄下。
#具體使用法如下:
ADD <源> <目標>
複製本地主機的源(預設為Dockerfile所在的目錄)到容器中的目標中,目標路徑不存在時會自動建立。
#具體使用法如下:
COPY <源> <目標>
COPY web/index.html /var/web/
指定容器啟動後執行的命令,多行只執行最後一行。並且不可被docker run提供的引數覆蓋。
#具體使用法如下:
ENTRYPOINT "command" "param1" "param2"
建立一個可以從本地主機或其它容器掛載的掛載點,一般用於存放資料。與docker run -v也可以實現此功能。
#具體使用法如下:
VOLUME [directory_name]
VOLUME /docker_data
指定容器執行時使用的使用者或UID,後面RUN、CMD、ENTRYPIONT都會使用此使用者來執行命令。
#具體使用法如下:
USER [username/uid]
指定RUN、CMD、ENTRYPIONT指定的命令的執行目錄。可以使用多個WORKDIR指令,後續引數如果是相對路徑,則會基於之前的命令指定的路徑。如:WORKDIR /data WORKDIR work。最終的路徑就是/data/work。path路徑也可以是環境變數。
#具體使用方法如下:
WORKDIR [path]
設定當前所建立的映象作為其它新建立映象的基礎映象時,所執行的操作指令。就是,這個映象建立後,如果其它映象以這個映象為基礎,會先執行這個映象的ONBUILD命令。
#具體使用法如下:
ONBUILD [INSTRUCTION]
接下來,我們通過構建一個Tomcat映象,來演示Dockerfile的使用方法,前提是安裝Docker環境,如何安裝Docker環境就不在此贅述了。請猛戳下面的文字:
[root@master tomcat]# ll
總用量 190504
-rw-r--r-- 1 root root 9552281 6月 7 15:07 apache-tomcat-8.5.31.tar.gz
-rw-r--r-- 1 root root 32 7月 3 09:41 index.jsp
-rw-r--r-- 1 root root 185515842 9月 20 2017 jdk-8u144-linux-x64.tar.gz
[root@master tomcat]# cat index.jsp
welcome to mingongge's web site
[root@master tomcat]# pwd
/root/docker/tomcat
[root@master tomcat]# vim Dockerfile
#config file start#
FROM centos
MAINTAINER mingongge <微信公眾號:民工哥技術之路>
#add jdk and tomcat software
ADD jdk-8u144-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.31.tar.gz /usr/local/
ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/
#config java and tomcat ENV
ENV JAVA_HOME /usr/local/jdk1.8.0_144
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
#config listen port of tomcat
EXPOSE 8080
#config startup command of tomcat
CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run
#end of config-file#
構建過程
[root@master tomcat]# docker build -t tomcat-web . #這個.不用註釋了吧相信懂的人自然懂的
Sending build context to Docker daemon 195.1 MB
Step 1/11 : FROM centos
---> 49f7960eb7e4
Step 2/11 : MAINTAINER mingongge <微信公眾號:民工哥技術之路>
---> Running in afac1e218299
---> a404621fac22
Removing intermediate container afac1e218299
Step 3/11 : ADD jdk-8u144-linux-x64.tar.gz /usr/local/
---> 4e22dafc2f76
Removing intermediate container b1b23c6f202a
Step 4/11 : ADD apache-tomcat-8.5.31.tar.gz /usr/local/
---> 1efe59301d59
Removing intermediate container aa78d5441a0a
Step 5/11 : ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/
---> f09236522370
Removing intermediate container eb54e6eb963a
Step 6/11 : ENV JAVA_HOME /usr/local/jdk1.8.0_144
---> Running in 3aa91b03d2d1
---> b497c5482fe0
Removing intermediate container 3aa91b03d2d1
Step 7/11 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
---> Running in f2649b5069be
---> 9cedb218a8df
Removing intermediate container f2649b5069be
Step 8/11 : ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
---> Running in 39ef620232d9
---> ccab256164fe
Removing intermediate container 39ef620232d9
Step 9/11 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
---> Running in a58944d03d4a
---> f57de761a759
Removing intermediate container a58944d03d4a
Step 10/11 : EXPOSE 8080
---> Running in 30681437d265
---> b906dcc26584
Removing intermediate container 30681437d265
Step 11/11 : CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run
---> Running in 437790cc642a
---> 95204158ee68
Removing intermediate container 437790cc642a
Successfully built 95204158ee68
通過構建的映象啟動容器
[root@master tomcat]# docker run -d -p 8080:8080 tomcat-web
b5b65bee5aedea2f48edb276c543c15c913166bf489088678c5a44fe9769ef45
[root@master tomcat]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b5b65bee5aed tomcat-web "/bin/sh -c '/usr/..." 5 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp vigilant_heisenberg
瀏覽器輸入http://server-ip:8080, 結果如下:
當我們執行docker pull xxx的時候,docker預設是從registry.docker.com這個地址上去查詢我們所需要的映象檔案,然後執行下載操作。這類的映象倉庫就是docker預設的公共倉庫,所有人都可以直接檢視或下載、使用,但是呢,基於網路原因,下載速度有限制比較慢。因此,我們在公司內部內網環境中使用dokcer,一般不會將映象檔案上傳到公網公共庫中。但內部共用使用就是個問題,所以,私有倉庫就由此產生了。
私有倉庫,就是本地(內網環境)組建的一個與公網公共庫功能相似的映象倉庫。組建好之後,我們就可以將打包好的映象提交到私有倉庫中,這樣內網其它使用者也可以使用這個映象檔案。
本文使用官方提供的registry映象來組建企業內網的私有映象倉庫
兩臺安裝好docker環境的主機
下載官方registry映象檔案
[root@master ~]# docker pull registry
Using default tag: latest
Trying to pull repository docker.io/library/registry ...
latest: Pulling from docker.io/library/registry
81033e7c1d6a: Pull complete
b235084c2315: Pull complete
c692f3a6894b: Pull complete
ba2177f3a70e: Pull complete
a8d793620947: Pull complete
Digest: sha256:672d519d7fd7bbc7a448d17956ebeefe225d5eb27509d8dc5ce67ecb4a0bce54
Status: Downloaded newer image for docker.io/registry:latest
[root@master ~]# docker images |grep registry
docker.io/registry latest d1fd7d86a825 5 months ago 33.3 MB
執行registry容器
[root@master ~]# mkdir /docker/registry -p
[root@master ~]# docker run -itd -v /docker/registry/:/docker/registry -p 5000:5000 --restart=always --name registry registry:latest
26d0b91a267f684f9da68f01d869b31dbc037ee6e7bf255d8fb435a22b857a0e
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
26d0b91a267f registry:latest "/entrypoint.sh /e..." 4 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp registry
引數說明
1)-itd:在容器中開啟一個偽終端進行互動操作,並在後臺執行;
2)-v:把宿主機的/docker/registry目錄繫結到容器/docker/registry目錄(這個目錄是registry容器中存放映象檔案的目錄),來實現資料的持久化;
3)-p:對映埠;存取宿主機的5000埠就存取到registry容器的服務了;
4)--restart=always:這是重新啟動的策略,假如這個容器異常退出會自動重新啟動容器;
5)--name registry:建立容器命名為registry,可自定義任何名稱;
6)registry:latest:這個是剛才pull下來的映象;
檢視遠端倉庫映象檔案
[root@master ~]# curl http://localhost:5000/v2/_catalog
{"repositories":[]}
同樣也可以使用瀏覽器存取http://server-ip:5000/v2/_cat... 結果相同,都是空的沒有任何檔案。
修改下載的映象源
[root@slave1 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors":["https://registry.docker-cn.com"]
}
[root@slave1 ~]# systemctl restart docker
下載測試映象
[root@slave1 ~]# docker pull nginx
Using default tag: latest
Trying to pull repository docker.io/library/nginx ...
latest: Pulling from docker.io/library/nginx
683abbb4ea60: Pull complete
6ff57cbc007a: Pull complete
162f7aebbf40: Pull complete
Digest: sha256:636dd2749d9a363e5b57557672a9ebc7c6d041c88d9aef184308d7434296feea
Status: Downloaded newer image for docker.io/nginx:latest
給映象打TAG
[root@slave1 ~]# docker tag nginx:latest 192.168.3.82:5000/nginx:v1
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.3.82:5000/nginx v1 649dcb69b782 8 hours ago 109 MB
docker.io/nginx latest 649dcb69b782 8 hours ago 109 MB
上傳映象
[root@slave1 ~]# docker push 192.168.3.82:5000/nginx:v1
The push refers to a repository [192.168.3.82:5000/nginx]
Get https://192.168.3.82:5000/v1/_ping: http: server gave HTTP response to HTTPS client
#注意這裡出現報錯提示,從提示資訊可以看出需要使用https的方式才能上傳,解決方案如下:
[root@slave1 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors":["https://registry.docker-cn.com"],
"insecure-registries":["192.168.3.82:5000"]
}
#新增私有映象伺服器的地址,注意書寫格式為json,有嚴格的書寫要求,需要重新啟動docker服務生效設定
[root@slave1 ~]# systemctl restart docker
[root@slave1 ~]# docker push 192.168.3.82:5000/nginx:v1
The push refers to a repository [192.168.3.82:5000/nginx]
6ee5b085558c: Pushed
78f25536dafc: Pushed
9c46f426bcb7: Pushed
v1: digest: sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7 size: 948
重新檢視映象倉庫
[root@master ~]# curl http://localhost:5000/v2/_catalog
{"repositories":["nginx"]}
[root@master ~]# curl http://localhost:5000/v2/nginx/tags/list
{"name":"nginx","tags":["v1"]}
#檢視有哪些版本
測試下載
#首先刪除使用者端主機之前從公共庫下載下來的映象檔案
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.3.82:5000/nginx v1 649dcb69b782 10 hours ago 109 MB
docker.io/nginx latest 649dcb69b782 10 hours ago 109 MB
[root@slave1 ~]# docker image rmi -f 649dcb69b782
Untagged: 192.168.3.82:5000/nginx:v1
Untagged: 192.168.3.82:5000/nginx@sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7
Untagged: docker.io/nginx:latest
Untagged: docker.io/nginx@sha256:636dd2749d9a363e5b57557672a9ebc7c6d041c88d9aef184308d7434296feea
Deleted: sha256:649dcb69b782d4e281c92ed2918a21fa63322a6605017e295ea75907c84f4d1e
Deleted: sha256:bf7cb208a5a1da265666ad5ab3cf10f0bec1f4bcb0ba8d957e2e485e3ac2b463
Deleted: sha256:55d02c20aa07136ab07ab47f4b20b97be7a0f34e01a88b3e046a728863b5621c
Deleted: sha256:9c46f426bcb704beffafc951290ee7fe05efddbc7406500e7d0a3785538b8735
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
#此時使用者端所有的映象檔案全部刪除
[root@slave1 ~]# docker pull 192.168.3.82:5000/nginx:v1
Trying to pull repository 192.168.3.82:5000/nginx ...
v1: Pulling from 192.168.3.82:5000/nginx
683abbb4ea60: Pull complete
6ff57cbc007a: Pull complete
162f7aebbf40: Pull complete
Digest: sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7
Status: Downloaded newer image for 192.168.3.82:5000/nginx:v1
[root@slave1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.3.82:5000/nginx v1 649dcb69b782 11 hours ago 109 MB
#可以看出,使用者端已正常從遠端伺服器拉取到所需要的映象檔案,其它內網伺服器也可以正常共用這臺映象服
以上步驟就是通過使用docker Registry快速搭建私有映象倉庫的過程與測試。我也其實也可以通過:利用 Harbor 搭建企業級私有映象倉庫。
Docker是一項非常流行的容器技術,現在在各行各業有著廣泛的使用。不過如何管理Docker容器是一個問題,所以我今天向大家介紹兩款Docker視覺化工具,希望對大家有所幫助。
Portainer是一款Docker視覺化管理工具,允許我們在網頁中方便的檢視和管理Docker容器。
要使用Portainer很簡單,執行下面兩條命令即可。這些命令會建立一個Portainer專用的卷,然後在8000和9000埠建立容器並執行。
$ docker volume create portainer_data$ docker run --name portainer -d -p 8000:8000 -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
然後在瀏覽器開啟對應地址,就會發現成功執行了。第一次執行的時候需要設定賬號,然後選擇要管理的Docker主機。
設定賬號
選擇要管理的主機
之後就可以看到本機上執行的Docker容器了,點選它們還可以進行容器的管理。左邊的條目可以管理卷、建立容器、檢視主機資訊等等。基本上該有的功能都有了,這也是我推薦的一個工具。
LazyDocker是基於終端的一個視覺化查詢工具,支援鍵盤操作和滑鼠點選。相比Portainer來說可能不那麼專業,不過對於開發者來說可能反而更加好用了。因為一般開發者都是使用命令列來執行Docker,偶爾需要圖形化檢視的時候,就可以使用LazyDocker這個工具。
官網演示圖
安裝LazyDocker也非常簡單,執行下面的命令即可。
docker run --rm -it -v \/var/run/docker.sock:/var/run/docker.sock \-v ~/.config/lazydocker:/.config/jesseduffield/lazydocker \lazyteam/lazydocker
當然如果發現LazyDocker挺好用,準備經常使用的話,還可以把它做成縮寫新增到shell組態檔中,這樣就可以將它變成一個簡單的命令。例如我用的是zsh,就將下面這樣新增到.zshrc檔案中。以後就可以直接用lzd來呼叫LazyDocker了。
alias lzd='docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v ~/.config/lazydocker:/.config/jesseduffield/lazydocker lazyteam/lazydocker'
然後就可以在終端中檢視Docker容器、映象和卷的資訊了。LazyDocker支援鍵盤操作和滑鼠點選,直接用滑鼠點選就可以檢視對應資訊了。
需要注意如果你的終端LazyDocker的圖形顯示的是亂的,不用擔心,只不過是顯示字型的問題。重新設定一下終端字型就可以解決了。
以上內容來自:https://www.toutiao.com/i6780...
Docker 社群已經建立了許多開源工具,它們能幫我們處理各種用例。作者在本文中推薦了 5 款認為最有用的 Docker 工具,分別是 Watchtower(自動更新 Docker 容器)、docker-gc(容器和映象的垃圾回收)、docker-slim(容器瘦身)、 rocker:突破 Dockerfile 的限制,以及 ctop(容器的類頂層介面)。
Docker 社群已經建立了許多開源工具,它們所能幫你處理的用例甚至會超出你的想象。
你可以在網上找到很多酷炫的 Docker 工具,其中大部分是開源的,都可以在 Github 上找到。在過去的兩年裡,我非常熱衷於 Docker,在大多數開發專案中都使用了它。當你開始使用 Docker 後,你會發現它適用的場景比你最初預想的還更多。你會希望 Docker 儘可能為你多做一點事,而它不會讓你失望的!
Docker 社群非常活躍,每天都會出現許多有用的工具,時時關注社群中發生的所有創新是很困難的。為了幫助你,我收集了一些我在日常工作中使用的又有趣又實用的 Docker 工具,這些工具提升了我的工作效率,減少了原本需要手工完成的工作。
向大家推薦一些實用工具:你應該知道的5個開源Docker工具...,Docker 服務終端 UI 管理工具,大家最終根據自己的使用習慣與實際生產需求來選擇合適自己的工具來管理Docker容器。
隨著線上服務的全面docker化,對docker容器的監控就很重要了。SA的監控系統是物理機的監控,在一個物理機跑多個容器的情況下,我們是沒法從一個監控圖表裡面區分各個容器的資源佔用情況的。
推薦大家看看這篇:打造高逼格、視覺化的Docker容器監控系統平臺
在平時的工作中,docker 接觸得很多,除了經常使用的 docker run ,docker stop 等命令,docker 還有很多十分有用但是卻不經常使用的命令,下面就來總結一下:
這個命令是用來檢視一個容器裡面的程序資訊的,比如你想檢視一個 nginx 容器裡面有幾個 nginx 程序的時候,就可以這麼做:
docker top 3b307a09d20d
UID PID PPID C STIME TTY TIME CMD
root 805 787 0 Jul13 ? 00:00:00 nginx: master process nginx -g daemon off;
systemd+ 941 805 0 Jul13 ? 00:03:18 nginx: worker process
我一般使用這兩個命令去下載打包 Kubernetes 的映象,因為你知道的國內的網速並不像國外那麼快。
docker save 可以把一個映象儲存到 tar 檔案中,你可以這麼做:
~ docker save registry:2.7.1 >registry-2.7.1.tar
#同時 docker load 可以把映象從 tar 檔案匯入到 docker 中
~ docker load < registry-2.7.1.tar
這個命令可以幫助你在命令列中方便的搜尋 DockerHub 中的映象,比如:
~ docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 13519 [OK]
jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1846 [OK]
richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable of… 780 [OK]
linuxserver/nginx An Nginx container, brought to you by LinuxS… 123
bitnami/nginx Bitnami nginx Docker Image 87 [OK]
tiangolo/nginx-rtmp Docker image with Nginx using the nginx-rtmp… 85 [OK]
jc21/nginx-proxy-manager Docker container for managing Nginx proxy ho… 73
alfg/nginx-rtmp NGINX, nginx-rtmp-module and FFmpeg from sou… 71 [OK]
nginxdemos/hello NGINX webserver that serves a simple page co… 57 [OK]
jlesage/nginx-proxy-manager Docker container for Nginx Proxy Manager 53 [OK]
nginx/nginx-ingress NGINX Ingress Controller for Kubernetes 37
......
當然這個功能在國內可能不會特別好用,因為......
這個命令可以幫助你實時獲取 docker 的各種事件資訊,比如建立了一個容器什麼的。
~ docker events
2020-07-28T21:28:46.000403018+08:00 image load sha256:432bf69f0427b52cad10897342eaf23521b7d973566354118e9a59c4d31b5fae (name=sha256:432bf69f0427b52cad10897342eaf23521b7d973566354118e9a59c4d31b5fae)
當你 docker run 了之後卻發現裡面有一些引數並不是你想要的狀態比如你設定的 nginx 容器 cpu 或者記憶體太小,這個時候你就可以使用 docker update 去修改這些引數。
~ docker update nginx --cpus 2
當你修改了一個映象,但是忘記了每一層的修改命令,或者你想檢視一個映象是怎麼構建的時候就可以使用這個命令,比如:
~ docker history traefik:v2.1.6
IMAGE CREATED CREATED BY SIZE COMMENT
5212a87ddaba 5 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 5 months ago /bin/sh -c #(nop) CMD ["traefik"] 0B
<missing> 5 months ago /bin/sh -c #(nop) ENTRYPOINT ["/entrypoint.… 0B
<missing> 5 months ago /bin/sh -c #(nop) EXPOSE 80 0B
<missing> 5 months ago /bin/sh -c #(nop) COPY file:59a219a1fb7a9dc8… 419B
<missing> 5 months ago /bin/sh -c set -ex; apkArch="$(apk --print-… 52.9MB
<missing> 5 months ago /bin/sh -c apk --no-cache add ca-certificate… 1.85MB
<missing> 6 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 6 months ago /bin/sh -c #(nop) ADD file:a1906f14a4e217a49… 4.81MB
這個命令可以檢視容器的退出狀態,比如:
~ docker wait 7f7f0522a7d0
0
這樣你就可以知道這個容器是正常退出的還是異常退出的了。
當你執行了一個容器但是想要暫停它執行的時候,你就可以使用這個命令。
~ docker pause 7f7f0522a7d0
當你執行了一個容器,但是你不知道容器裡修改了哪一些檔案的時候可以使用這個命令,比如:
~ docker diff 38c59255bf6e
C /etc
A /etc/localtime
C /var
C /var/lib
A /var/lib/registry
這個是 docker 內建的監控命令,當你想要檢視當前主機下所有容器佔用記憶體和 cpu 的情況的時候就可以使用這個命令。
~ docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
1c5ade04e7f9 redis 0.08% 17.53MiB / 47.01GiB 0.04% 10.9GB / 37GB 0B / 0B 4
afe6d4ebe409 kafka-exporter 0.09% 16.91MiB / 47.01GiB 0.04% 1.97GB / 1.53GB 752MB / 0B 23
f0c7c01a9c34 kafka-docker_zookeeper 0.01% 308.8MiB / 47.01GiB 0.64% 20.2MB / 12.2MB 971MB / 3.29MB 28
da8c5008955f kafka-docker_kafka-manager 0.08% 393.2MiB / 47.01GiB 0.82% 1.56MB / 2.61MB 1.14GB / 0B 60
c8d51c583c49 kafka-docker_kafka 1.63% 1.256GiB / 47.01GiB 2.67% 30.4GB / 48.9GB 22.3GB / 5.77GB 85
......
很多人最終還是決定使用 Docker 解決問題。 Docker 的優點很多,比如:
儘管如此,眾多使用者仍然只是把容器當做常見的虛擬機器器,而忘記了容器的一個重要特性:
正因為這一特點,一些使用者需要改變他們對容器的觀念,為了更好的使用與發揮 Docker 容器的價值,有一些事情是絕對不應該做的:
容器可能會被中斷、被替換或遭到破壞。在容器中執行的 1.0 版應用程式很容易就會被 1.1 版取代,而不會對資料造成影響或導致資料丟失。因此,如果需要儲存資料,請儲存在卷 (volume) 中。在這一情況下,還應注意兩個容器是否會在同一個捲上寫入資料,這將導致損壞。請確保應用程式適用於寫入共用的資料儲存。
所以他們大多會認為,應該將應用程式部署到現有正在執行的容器中。在需要不斷部署和偵錯的開發階段,可能確實如此;但對於 QA 和生產的持續交付 (CD) 渠道,應用程式應當是映象的一部分。切記:容器轉瞬即逝。
大尺寸的映象難以分配。請確保僅使用必需檔案和庫來執行應用程式。不要安裝不必要的封包,也不要執行「更新」(yum update),這些操作會把大量檔案下載到新的映象層。
為了有效利用多層檔案系統,請始終為作業系統建立屬於自己的基本映象層,然後為使用者名稱定義建立一個層,為執行時安裝建立一個層,為設定建立一個層,最後再為應用程式建立一個層。這樣,重新建立、管理和分配映象就會容易些。
換句話說,不要使用"docker commit"命令來建立映象。這一映象建立方法不可複製,因此應完全避免使用。請始終使用 Dockerfile 或其他任何可完全複製的 S21(從原始碼到映象)方法,如此一來,如果儲存在原始碼控制儲存庫 (GIT) 中,就可以跟蹤 Dockerfile 的變更情況。
最新版標籤就像 Maven 使用者的「快照」(SNAPSHOT) 一樣。容器具有多層檔案系統這一基本特徵,所以我們鼓勵使用標籤。相信誰也不願意在構建了幾個月的映象後,突然發現應用程式因為父層(即 Dockerfile 中的 FROM)被新版本取代而無法執行(新版本無法向後相容或從構建快取中檢索的「最新「版有誤)這樣的意外吧?在生產過程中部署容器時也應避免使用」最新版「標籤,這是因為無法跟蹤當前執行的映象版本。
容器只執行一個程序(HTTP 守護行程、應用程式伺服器、資料庫)時效果最佳,但如果執行一個以上程序,在管理和檢索紀錄檔以及單獨更新程序時就會遇到很多麻煩。
不要在映象中對任何使用者名稱/密碼進行寫死操作。請使用環境變數從容器外部檢索資訊。Postgres 映象就是這一原理的極佳詮釋。
「預設情況下,Docker 容器以 root 使用者許可權執行。隨著 Docker 技術日趨成熟,能夠使用的安全預設選項越來越多。目前,要求 root 對其他使用者來說較為危險,另外,不是所有環境都能夠使用 root。映象應使用 USER 指令來為容器的執行指定非 root 使用者。」(摘自《Docker 映象作者指南》(Guidance for Docker Image Authors))
每個容器都有自己的內部 IP 地址,如果啟動然後停止容器,內部 IP 地址可能會發生變化。如果你的應用程式或微服務需要和另一個容器進行通訊,請使用環境變數在容器之間傳遞相應的主機名和埠。
監控已經越來越受到開發者們的重視,實時監控 Docker 的方法,這裡推薦 Cloudinsight。 不同於一些需要自寫指令碼的監控手段,Cloudinsight 作為一家免費的 SaaS 服務,能夠一鍵監控 Docker,且擁有很棒的視覺化介面。除此之外,Cloudinsight 還支援多種作業系統、資料庫等的監控,能夠一體化展示所有被監控的系統基礎元件的效能資料。
原文:https://my.oschina.net/cllgee...
工作流程:
1,部署git
如果公司內部有直接克隆就可以
git clone [email protected]:/home/git/solo.git
2,部署Jenkins環境
部署傳送門:Jenkins+Maven+Svn實現程式碼自動打包與釋出
3,部署私有映象倉庫
注意:docker 倉庫 由於https 認證,所有需要pull的使用者端,需要修改組態檔
[root@linux-node1 ~]# vim /etc/sysconfig/docker
# Modify these options if you want to change the way the docker daemon runs
OPTIONS='--selinux-enabled --insecure-registry 192.168.56.11:5000'
4,所有主機安裝docker
1)安裝依賴包
yum install -y yum-utils device-mapper-persistent-data lvm2`
2)新增Docker軟體包源:
yum-config-manager
--add-repo
https://download.docker.com/linux/centos/docker-ce.repo
3)安裝Docker CE
yum install docker-ce -y`
4)設定加速器
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://bc437cce.m.daocloud.io`
#因為預設源會去國外獲取資料,所以會慢可以超時,這是我們就需要設定加速器指向國內源https://www.daocloud.io/
5)啟動並開機啟動
# systemctl start docker
# systemctl enable docker
【Apache、Nginx、Tomcat、LNMP、LAMP、LNTP】
JAVA程式必須有JDK環境才可以執行,為了減少映象大小及提高效能,這裡直接把JDK放到宿主機上,容器以掛載形式使用。
1,安裝jdk
#rz 把tar包上傳,解壓後放到指定目錄
rz.......
tar -zxvf jdk-8u60-linux-x64.tar.gz
mv jdk1.8.0_60 /usr/local/jdk1.8
2,擬寫Dockerfile
# cat Dockerfile
FROM centos:7
#他的媽媽是誰
MAINTAINER www.aliangedu.com
#他的爸爸是誰
ENV VERSION=8.5.33
#tomcat版本
ENV JAVA_HOME /usr/local/jdk
#jdk 絕對路徑
RUN yum install wget -y
#執行的命令
RUN wget http://mirrors.shu.edu.cn/apache/tomcat/tomcat-8/v${VERSION}/bin/apache-tomcat-${VERSION}.tar.gz &&
tar zxf apache-tomcat-${VERSION}.tar.gz &&
mv apache-tomcat-${VERSION} /usr/local/tomcat &&
rm -rf apache-tomcat-${VERSION}.tar.gz /usr/local/tomcat/webapps/* &&
mkdir /usr/local/tomcat/webapps/ROOT
EXPOSE 8080
#程式使用的埠
CMD /usr/local/tomcat/bin/catalina.sh run
#執行tomcat目錄下的啟動指令碼,這裡面遇到坑,就是-v 將宿主機jdk目錄掛在到容器/usr/local/jdk 時候,因為映象按照dockerfile去打,那麼在執行命令的時候就會找不到路徑,所以我臨時刪除了,EXPOSE與CMD 2行,然後重新打包,使用 -p 指定埠,然後進入容器,手工啟動tomcat的方式,進行
3,構建映象
docker build -t 192.168.56.11:5000/tomcat-85:latest -f dockerfile .
#最後這個點。代表當前路徑,在製作映象時,會記錄上下文內容
4,上傳到docker 映象倉庫
root@node02 scripts]# docker push 192.168.56.11:5000/tomcat-85:latest
5,啟動映象 測試
[root@node02 scripts]# docker run -it -d -p 8080:8080 -v /usr/local/jdk1.8:/usr/local/jdk 192.168.56.11:5000/tomcat-8:latest
[root@3addff07c464 ROOT]# echo "123" >index.jsp
1.主頁面 -> 系統管理 -> 全域性工具設定
指定JDK、Maven路徑,Git保持預設:
2.jenkins安裝必要外掛
主頁面 -> 系統管理 ->管理外掛:
安裝SSH與Git Parameter外掛。
外掛說明:
3,設定SSH外掛
第一步:先建立一個用於連線Docker主機的憑證 (有許可權的使用者)
主頁面 -> 憑據 -> 系統 -> 右擊全域性憑據 -> 新增憑據:
輸入連線Docker主機的使用者名稱和密碼:
第二步:新增SSH遠端主機
主頁面 -> 系統管理 -> 系統設定 -> SSH remote hosts:
問題:當以普通使用者身份去使用docker images時,出現以下錯誤:
# git clone https://github.com/b3log/solo
# cd solo
移除舊的推播地址,新增新的:
# git remote remove origin
# git remote add origin [email protected]:qqq/solo.git
提交程式碼到Git倉庫並建立tag:
# touch src/main/webapp/a.html
# git add .
# git commit -m 「a」
建立標籤:
# git tag 1.0.0
推播到Git伺服器:
# git push origin 1.0.0
登陸gitlab檢視solo專案:
1.主頁面 -> 新建任務 -> 輸入任務名稱,構建一個Maven專案:
注意:如果沒有顯示「構建一個Maven專案」選項,需要在管理外掛裡安裝「Maven Integration plugin」外掛。
設定Git引數化構建:
2.動態獲取Git倉庫tag,與使用者互動選擇Tag釋出:【也可以設定分支】
3.指定專案Git倉庫地址:
修改*/master為$Tag,Tag是上面動態獲取的變數名,表示根據使用者選擇打程式碼版本。
4.設定maven構建命令選項:
clean package -Dmaven.test.skip=ture
利用pom.xml檔案構建專案。
在Jenkins本機映象構建與推播到映象倉庫,並SSH遠端連線到Docker主機使用推播的映象建立容器:
上圖中 命令內容如下:
REPOSITORY=192.168.56.11:5000/solo:${Tag}
# 構建映象
cat > Dockerfile << EOF
FROM 192.168.56.11:5000/tomcat-8:latest
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY target/*.war /usr/local/tomcat/webapps/ROOT.war
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
EOF
docker build -t $REPOSITORY .
# 上傳映象
docker push $REPOSITORY
上圖中Command 內容如下:
REPOSITORY=192.168.56.11:5000/solo:${Tag}
# 部署
sudo docker rm -f blog-solo |true
sudo docker image rm $REPOSITORY |true
sudo docker container run -d --name blog-solo -v /usr/local/jdk1.8:/usr/local/jdk -p 8080:8080 $REPOSITORY
# -d 後臺執行 ,-v 掛在目錄,-p 對映埠,後面是映象
注:容器名稱blog-solo,暴露宿主機埠8080,即使用宿主機IP 192.168.56.12:8080 存取blog-solo專案。
blog-solo專案已設定完成,開始構建:
選擇tag,開始構建:
點選左下角構建歷史裡,右擊第一個檢視控制檯輸出:
構建詳細內容
構建成功
存取:192.168.56.12:8080 檢視部署結果
調整專案存取地址
進入容器,切換到專案目錄
vi WEB-INF/classes/latke.properties
#### Server ####
# Browser visit protocol
serverScheme=http
# Browser visit domain name
serverHost=192.168.56.12
# Browser visit port, 80 as usual, THIS IS NOT SERVER LISTEN PORT!
serverPort=8080
調整後,重新啟動tomcat,再次驗證,OK,結果如下:
至此,自動化CI環境搭建完成,你可以模擬提交程式碼並打tag測試自動化釋出流程。
檢視docker.sock許可權
[root@node03 ~]# ll /var/run/docker.sock
srw-rw---- 1 root docker 0 9月 4 21:55 /var/run/docker.sock
解決方法:【免sudo 使用docker images 】
[root@node03 ~]# sudo groupadd docker
##groupadd:「docker」組已存在
[root@node03 ~]# sudo gpasswd -a jenkins docker
##正在將使用者「jenkins」加入到「docker」組中
[root@node03 ~]# sudo service docker restart
##重新啟動服務
[root@node03 ~]# newgrp - docker
##重新載入group 組資訊,一定要輸入這條命令,否則無法載入最新組內容,因為有快取
原文:https://www.toutiao.com/a6602...
這裡主要是為了記錄在使用 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/
# 4.改動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 命令單純複製檔案內容的話,就會出現屬性不一致的情況,同時還會有一定的安全問題。
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
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
對 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
不停止伺服器上面執行的容器,重新啟動 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
}
]
}
找不到對應容器程序是最嚇人的
問題起因:今天遇到 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
容器存在問題話,記得優先在官網查詢
問題起因:今天登陸之前部署的 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
瞭解 Docker 的四種網路模型
問題起因:在本機部署 Nginx 容器想代理本機啟動的 Python 後端服務程式,但是對程式碼服務如下的設定,結果存取的時候一直提示 502 錯誤。
# 啟動Nginx服務
$ docker run -d -p 80:80 $PWD:/etc/nginx 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
nginx
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
匯流排錯誤看到的時候還是挺嚇人了
問題起因:在 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
匯流排錯誤看到的時候還是挺嚇人了
問題起因:我們將服務部署到 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.
啟動的容器網路無法相互通訊,很是奇怪!
問題起因:我們在使用 Docker 啟動服務的時候,發現有時候服務之前可以相互連通,而有時間啟動的多個服務之前卻出現了無法存取的情況。究其原因,發現原來是因為使用的內部私有地址網段不一致導致的。有點服務啟動到了 172.17 - 172.31 的網段,有的服務跑到了 192.169.0 - 192.168.224 的網段,這樣導致服務啟動之後出現無法存取的情況。
解決方法:上述問題的處理方式,就是手動指定 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": []
}
}
}
使用 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,所以啟動的時候被認為是同一個,這就出現了上述的問題。如果需要深入瞭解的話,可以去看對應原始碼。
# 可以將目錄結構調整為如下所示
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
在編寫指令碼的時候常常會執行 docker 相關的命令,但是需要注意使用細節!
問題起因:CI 更新環境執行了一個指令碼,但是指令碼執行過程中報錯了,如下所示。通過對應的輸出資訊,可以看到提示說正在執行的裝置不是一個 tty。
隨即,檢視了指令碼發現報錯地方是執行了一個 exec 的 docker 命令,大致如下所示。很奇怪的是,手動執行或直接調指令碼的時候,怎麼都是沒有問題的,但是等到 CI 呼叫的時候怎麼都是有問題。後來好好看下下面這個命令,注意到 -it 這個引數了。
# 指令碼呼叫docker命令
docker exec -it <container_name> psql -Upostgres ......
我們可以一起看下 exec 命令的這兩個引數,自然就差不多理解了。
-i/-interactive #即使沒有附加也保持 STDIN 開啟;如果你需要執行命令則需要開啟這個選項
-t/–tty #分配一個偽終端進行執行;一個連線使用者的終端與容器 stdin 和 stdout 的橋樑
解決方法:docker exec 的引數 -t 是指 Allocate a pseudo-TTY 的意思,而 CI 在執行 job 的時候並不是在 TTY 終端中執行,所以 -t 這個引數會報錯。
在 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 選項。
-i/-interactive #即使沒有附加也保持 STDIN 開啟;如果你需要執行命令則需要開啟這個選項
-t/–tty #分配一個偽終端進行執行;一個連線使用者的終端與容器 stdin 和 stdout 的橋樑
compose 裡邊環境變數帶不帶引號的問題!
問題起因:使用過 compose 的同學可能都遇到過,我們在編寫啟動組態檔的時候,新增環境變數的時候到底是使用單引號、雙引號還是不使用引號。時間長了,可能我們總是三者是一樣的,可以相互使用。但是,直到最後我們發現坑越來越多,越來越隱晦。
反正我是遇到過很多是因為新增引號導致的服務啟動問題,後來得出的結論就是一律不適用引號。裸奔,體驗前所未有的爽快!直到現在看到了 Github 中對應的 issus 之後,才終於破案了。
# 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 組態檔,能不使用引號就不適用引號。
無法刪除映象,歸根到底還是有地方用到了!
問題起因:清理服器磁碟空間的時候,刪除某個映象的時候提示如下資訊。提示需要強制刪除,但是發現及時執行了強制刪除依舊沒有效果。
# 刪除映象
$ 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
bash
# 刪除懸空映象
$ docker rmi $(docker images --filter "dangling=true" -q --no-trunc)
切換 Docker 啟動使用者的話,還是需要注意下許可權問題的!
問題起因:我們都知道在 Docker 容器裡面使用 root 使用者的話,是不安全的,很容易出現越權的安全問題,所以一般情況下,我們都會使用普通使用者來代替 root 進行服務的啟動和管理的。今天給一個服務切換使用者的時候,發現 Nginx 服務一直無法啟動,提示如下許可權問題。因為對應的組態檔也沒有設定 var 相關的目錄,無奈