安裝
安裝步驟可以直接參考官方文檔:
- CentOS https://docs.docker.com/engine/install/centos/
- Ubuntu https://docs.docker.com/engine/install/ubuntu/
- Windows(10+)https://docs.docker.com/desktop/windows/install/
鏡像加速
從 Docker Hub 上拉取鏡像可能會比較慢,可以使用國內的一些鏡像加速器服務:
- 阿里云: 需要自行注冊獲取地址,點擊管理控制臺 -> 登錄賬號 -> 右側鏡像工具 -> 鏡像加速器 -> 復制加速器地址
- 百度云:https://mirror.baidubce.com
- 網易云:https://hub-mirror.c.163.com
CentOS、Ubuntu 可以在/etc/docker/daemon.json
中配置鏡像加速器:
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
Windows 則可以在Settings -> Docker Engine -> 右側 JSON
中配置上邊的內容。
優勢
傳統的虛擬機需要實現硬件資源的虛擬化,而 Docker 直接使用物理機上的硬件資源;新建一個容器時不需要像虛擬機那樣重新加載一個操作系統內核,而直接使用宿主機的操作系統內核;因此 Docker 更加的輕量級、運行效率更高!
啟停命令
CentOS 下 一些 Docker 常用的啟停命令:
- 啟動:
systemctl start docker
- 停止:
systemctl stop docker
- 重啟:
systemctl restart docker
- 開機啟動:
systemctl enable docker
- 查看狀態:
systemctl status docker
鏡像(Image)
Docker 中的鏡像是一個特殊的分層文件系統,主要提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如匿名卷、環境變量、用戶等)。鏡像不包含任何動態數據,是只讀的,其內容在構建之后也不會被改變。
Docker 在設計鏡像時,利用 Union FS(聯合文件系統)技術,將其設計為分層存儲的架構,分層存儲的特點使得鏡像復用、定制變的更為容易。可以用現有的鏡像為基礎層,來添加新的層,以定制自己所需的內容。鏡像是逐層構建的,前一層是后一層的基礎,每一層構建完就不會再發生改變。
https://docs.docker.com/engine/reference/commandline/image/
列出已下載的鏡像:
docker image ls、docker images
只列出鏡像 id:
docker image ls -q
-
拉取鏡像:
docker pull [鏡像倉庫地址] 倉庫名[:標簽]
- 鏡像倉庫地址默認是
Docker Hub(docker.io)
- 倉庫名由
用戶名/軟件名
組成,對于 Docker Hub 如果不指定用戶名默認是library
,也就是官方鏡像
- 鏡像倉庫地址默認是
搜索鏡像:
docker search 倉庫名:標簽
查看鏡像、容器、數據卷、緩存占用的空間:
docker system df
刪除指定鏡像:
docker image rm 倉庫名[:標簽]/鏡像id
刪除無用鏡像:
docker image prune
-
保存、加載鏡像:
-
docker save 倉庫名[:標簽]/鏡像ID > 文件名.tar
,將鏡像保存為文件,會保存該鏡像的的所有歷史記錄 -
docker load 文件名.tar
,從文件加載鏡像,會恢復鏡像名、標簽等信息
-
-
制作鏡像:
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
,將容器保存為鏡像- OPTIONS 可以指定
-a
(作者信息);-m
(提交信息) - CONTAINER 可以是容器名、容器ID
- [REPOSITORY[:TAG]],生成鏡像的名字、版本等
- 最終的鏡像會添加大量無關內容,導致鏡像體積大;外界無法知道鏡像的制作過程,執行了那些命令;所以一般不會使用該命令制作鏡像,而是使用
Dockerfile
。
- OPTIONS 可以指定
容器(Container)
鏡像和容器的關系,類似面向對象程序設計中的類和實例,鏡像是靜態的定義,容器是鏡像運行時的實體。容器可以被創建、啟動、停止、刪除、暫停等。
容器的本質進程,它運行在自己的獨立的命名空間。容器可以擁有自己的文件系統、網絡配置、進程空間等,可以看做是一個簡易的 Linux 環境。容器內的進程是運行在一個隔離的環境里,使用起來,就好像是在一個獨立于宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主運行更加安全。也因為這種隔離的特性,很多人初學 Docker 時常常會混淆容器和虛擬機。
容器運行時,會以鏡像為基礎層,在其上創建一個當前容器的運行時需要的存儲層,容器存儲層的生命周期和容器一樣,任何保存于容器存儲層的信息都會隨容器刪除而丟失。
根據 Docker 的最佳實踐,容器不應該向其存儲層內寫入任何數據,容器存儲層要保持無狀態化。所有的文件寫入操作,都應該使用數據卷(Volume)
或者綁定宿主目錄
,其性能和穩定性更高。數據卷的生命周期獨立于容器,因此容器刪除或者重新運行之后,數據卻不會丟失。
https://docs.docker.com/engine/reference/commandline/container/
- 啟動容器:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
,OPTIONS 常用的參數如下:-
--name="容器名"
,給容器指定一個名稱,不指定則隨機分配 -
-d
,在后臺運行容器、并返回容器 ID,也稱作守護狀態運行 -
-i
,以交互模式運行容器,通常和 -t 一起使用 -
-t
,給容器重新分配一個偽輸入終端,通常和 -i 一起使用 -
-P/-p
,指定端口映射,詳細內容見網絡部分
-
使用 ubuntu 鏡像以交互模式啟動一個容器,并在容器內執行 /bin/bash 命令,得到一個交互式終端,退出終端可以使用exit
:
docker run -it ubuntu:18.04 /bin/bash
-
列出指定容器:
docker ps [OPTIONS]
,OPTIONS 常用的參數如下:-
-a
,列出當前所有運行的容器、歷史上運行過的容器 -
-l
,列出最近創建的容器 -
-n
,列出最近創建的 n 個容器 -
-q
,可以上前幾個參數配合使用,只顯示容器編號
-
-
退出容器:在容器的交互模式下,退出終端
-
exit
,會停止容器的運行 -
ctrl + q + p
,不會停止容器
-
停止容器:
docker stop 容器ID/容器名
啟動停止運行的容器:
docker start 容器ID/容器名
重啟容器:
docker restart 容器ID/容器名
強制停止容器:
docker kill 容器ID/容器名
刪除停止運行的容器:
docker rm 容器ID/容器名
,刪除運行中的容器需要添加-f
查看容器日志:
docker logs -f 容器ID/容器名
-
進入容器:使用 -d 參數啟動的后臺運行容器,使用如下命令可進入交互終端:
-
docker attach 容器ID/容器名
,執行exit
會導致容器停止 -
docker exec -it 容器ID/容器名 /bin/bash
,執行exit
不會停止容器
-
容器內拷貝文件到宿主機:
docker cp 容器ID:容器內路徑 目標主機路徑
,反過來拷貝也是類似的-
導入、導出容器快照:
-
docker export 容器ID/容器名 > 文件名.tar
,導出容器快照(容器文件系統)到指定文件,會丟失所有元數據和歷史記錄,僅保存容器當時的狀態 -
cat 文件名.tar | docker import - 用戶名/鏡像名:鏡像版本號
,從容器快照文件導入新鏡像,可以指定鏡像名、標簽等信息 -
docker import URL
,從 URL 導入鏡像
-
數據存儲
默認情況下,容器內產生的數據存儲在其內部的可寫層,其它進程很難訪問這些數據,或者將其移動到其它地方,而且數據會隨著容器的刪除而丟失。容器內的可寫存儲層需要的存儲驅動使用了聯合文件系統,相比直接將數據存在主機目錄性能也會差一些。
https://docs.docker.com/storage/
Docker 提供了如下兩種方式將容器數據存儲到宿主機上,也稱作目錄掛載:
-
Volumes
,數據卷,將容器數據存儲到由 Docker 管理的宿主機目錄中(Linux 上是 /var/lib/docker/volumes/),它和宿主機的核心功能隔離,一個數據卷可以掛載到多個容器,實現容器間數據共享,這也是 Docker 推薦的方式。掛載時只需要指定數據卷的名稱,適合掛載數據庫等。
docker run -d -p 8008:80 --name web -v nginx:/usr/share/nginx/html nginx
通過-v
命令將名為nginx
的數據卷掛載到容器的/usr/share/nginx/html
目錄,如果數據卷不存在則會隱式創建,也可以顯示創建,docker volume create xxx
。此時如果數據卷為空則掛載到的容器目錄中的數據會被復制到數據卷中;如果數據卷不為空則數據卷中的數據會覆蓋容器目錄的數據。我們可以根據需要配置多組-v
命令。
也可以使用--mount
命令,但如果數據卷不存在會報錯。
-
Bind mounts
,可以將數據存儲在宿主機上的任意目錄,掛載時需要指定宿主機上目錄的絕對路徑,也可以掛載到多個容器上,適合掛載配置文件等。
docker run -d -p 8008:80 --name web -v /opt/software/nginx:/usr/share/nginx/html nginx
同樣使用-v
命令,這里需要指定宿主機目錄的絕對路徑,如果目錄不存在會自動創建;注意,宿主機目錄的數據會直接覆蓋容器目錄的數據,這里和數據卷是有區別的。這里也可以使用--mount
指令。
Dockerfile
Dockerfile 是用來構建 Docker 鏡像的文本文件,其中包含了一條條的指令,每一條指令(指令的內容描述了該層應當如何構建)會構建鏡像的一層。
https://docs.docker.com/engine/reference/builder/
Dockerfile 指令:
-
FROM
,指定基礎鏡像,FROM 是必需的指令,并且必須是第一條指令;除了指定現有鏡像為基礎鏡像外,還可以指定名為scratch
的特殊鏡像,它表示不以任何鏡像為基礎,接下來所寫的指令將作為鏡像第一層開始存在 -
RUN
,用來執行命令行命令,通常用于安裝應用和軟件包,有兩種格式:- shell 格式:RUN <命令>,類似直接在命令行輸入命令,推薦使用該格式
- exec 格式:RUN ["可執行文件", "參數1", "參數2"],類似函數調用的形式
-
EXPOSE
,容器運行時對外暴露的端口,格式為EXPOSE <端口1> [<端口2>...]
,就是-p <宿主端口>:<容器端口>
中的容器端口 -
WORKDIR
,指定容器創建后,終端登錄進來的默認工作目錄,不存在會自動創建,格式為WORKDIR <工作目錄路徑>
-
USER
,指定以什么樣的用戶身份去執行鏡像,默認是 ROOT 用戶,格式為USER <用戶名>[:<用戶組>]
-
ENV
,設置環境變量,可以在其它指令中使用($key),格式為ENV <key> <value>
或者ENV <key>=<value>
-
VOLUME
,定義匿名數據卷,防止運行時用戶忘記將需要的文件目錄掛載為數據卷,當然運行容器時也可以覆蓋這個掛載設置 -
COPY
,將宿主機下的文件拷貝到鏡像,使用 COPY 指令,源文件的各種元數據都會保留,比如讀、寫、執行權限、文件變更時間等。有兩種格式(--chown=<user>:<group> 選項來改變文件的所屬用戶及所屬組):- COPY [--chown=<user>:<group>] <源路徑>... <目標路徑>
- COPY [--chown=<user>:<group>] ["<源路徑1>",... "<目標路徑>"]
-
ADD
,將宿主機下的文件拷貝到鏡像,會自動下載 URL、解壓 tar 壓縮包,格式和 COPY 指令基本一樣 -
CMD
,指定容器主進程的啟動程序、參數,注意,執行 docker run 時鏡像名/ID 后的命令會替換 CMD 的配置,CMD 有兩種格式:- shell 格式:CMD <命令>
- exec 格式:CMD ["可執行文件", "參數1", "參數2"...],推薦使用該格式
-
ENTRYPOINT
,作用和 CMD 一樣,都是指定容器主進程的啟動程序、參數,但是執行 docker run 時鏡像名/ID 后面的命令不會覆蓋掉 ENTRYPOINT 配置的內容,而且后面的命令會作為參數傳遞給 ENTRYPOINT 指定的啟動程序- ENTRYPOINT 也有 shell 和 exec 兩種格式,和 CMD 類似
- 如果 ENTRYPOINT 需要指定變化的參數,可以結合 CMD 一起使用,此時 CMD 的作用發生了變化不再是運行啟動程序,而是將 CMD 的內容作為動態參數傳遞給 ENTRYPOINT
FROM centos
ENV MYPATH /usr/local
WORKDIR $MYPATH
# CentOS 8停止更新后,使用yum安裝程序的時候會報錯,需要做如下修改
RUN cd /etc/yum.repos.d/ \
&& sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* \
&& sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* \
&& wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
&& yum clean all \
&& yum makecache
# 安裝vim
RUN yum -y install vim
# 安裝ifconfig
RUN yum -y install net-tools
# 安裝java8,以及lib庫
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
ADD jdk-8u301-linux-x64.tar.gz /usr/local/java
# 配置java環境變量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_301
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
EXPOSR 8081
CMD echo $MYPATH
CMD echo "---------success----------"
CMD /bin/bash
構建鏡像
一般我們會創建一個名為Dockerfile
的文件,然后通過上邊的指令編寫構建鏡像的腳本,最后通過如下命令完成就像的構建:
docker build -t 鏡像名:TAG .
注意命令最后邊有一個.
符號,表示執行指令的當前目錄,也就是上下文目錄
,docker build 命令會將該目錄下的內容打包交給 Docker 引擎以幫助構建鏡像。
默認情況下,如果不額外指定 Dockerfile 文件的話,會將上下文目錄下的名為 Dockerfile 的文件作為 Dockerfile,當然也可以用-f ../Dockerfile.txt
參數指定 Dockerfile 的文件名以及相對上下文路徑的存放目錄。
一般來說,應該將 Dockerfile 文件放在一個空目錄下或者項目根目錄下。如果該目錄下沒有所需文件,那么應該把所需文件復制一份過來。如果目錄下有些文件不希望構建時上傳給 Docker 引擎,那么可以用 .gitignore 一樣的語法寫一個.dockerignore
文件來忽略掉它們。
網絡
外部訪問容器
要從外部訪問容器內運行的網絡應用時,可以通過 -P 或 -p 參數來指定端口映射:
-
-P
,Docker 會隨機映射一個可用的宿主機端口到內部容器開放的網絡端口 -
-p
,指定需要映射的端口,一個指定端口上只可以綁定一個容器。支持的格有:-
hostPort:containerPort
,映射到本地的指定端口 -
ip:hostPort:containerPort
,映射到指定地址的指定端口 -
ip::containerPort
,映射到指定地址的任意端口
-
-
docker port <container name/id> containerPort
,查看指定容器端口映射的外部端口配置
容器互聯
-
docker network create [-d 網絡類型] <name>
,創建網絡,網絡類型默認為bridge
-
docker network ls
,查看已有網絡 -
docker network rm <name/NETWORK ID>
,刪除指定網絡
我們可以創建一個網絡,然后在運行容器時使用--network
指定要連接到的網絡,這樣不同容器可以運行在同一網絡,實現容器間的互聯:
docker network create -d bridge net007
docker run -d -p 8008:80 --name web -v nginx:/usr/share/nginx/html --network net007 nginx
docker run -d -p 8008:80 --name web2 -v nginx:/usr/share/nginx/html --network net007 nginx
這樣可以通過 ping 命令來驗證兩個容器是否可以互相通信,例如進入 web 容器執行ping web2
。需要先安裝 ping:
apt-get update
apt install iputils-ping
運行容器時如果不指定網絡,容器間也是可以通過 ip 互聯的,但是容器內的 ip 可能會變化,所以運行容器時可以指定網絡然后用容器名通信。
Docker compose
Compose 項目是 Docker 官方的開源項目,用于定義和運行多個容器的工具,實現對 Docker 容器集群的快速編排,簡單的理解就是處理需要多個容器相互配合來完成某項任務的場景。
Compose 中有兩個重要的概念:
- 服務 (service):一個應用的容器
- 項目 (project):由一組關聯的應用容器組成的一個完整業務單元,在
docker-compose.yml
文件中定義。
Compose 的默認管理對象是項目,通過子命令對項目中的一組容器進行便捷地生命周期管理。
例如一個 Web 項目,除了 Web 服務本身,可能還需要MySQL、Redis、Nginx等服務,使用 Compose 可以編寫一個docker-compose.yml
文件來定義一組相關聯的應用容器為一個項目,控制容器啟動的順序,實現管理多個應用容器等需求,而不用單獨去維護每個容器。
安裝:https://docs.docker.com/compose/install/compose-plugin/
編寫 Compose 模板文件
https://docs.docker.com/compose/compose-file/
模板文件的默認名稱是docker-compose.yml
,即一個YAML
格式的文件。
version: "3"
services:
docker_test:
image: docker_test:v1
container_name: dtv1
ports:
- "7001:7001"
volumes:
- docker_test_data:/tmp
networks:
- net007
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /opt/software/edis/redis.conf:/etc/redis/redis.conf
- redis_data:/data
networks:
- net007
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'mytest'
MYSQL_USER: 'user01'
MYSQL_PASSWORD: '123456'
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- /opt/software/mysql/conf/my.cnf:/etc/my.cnf
- /opt/software/mysql/init:/docker-entrypoint-initdb.d
networks:
- net007
command: --default-authentication-plugin=mysql_native_password # 解決外部無法訪問
networks:
net007:
volumes:
docker_test_data:
redis_data:
mysql_data:
在docker-compose.yml
文件目錄下運行 Compose 項目:
docker-compose up
-
version
,指定 Compose 模板文件版本,和 Docker 版本有對應關系 -
services
,配置具體的服務,我們這里設計三個服務 docker_test(一個 SpringBoot 服務)、redis、mysql。注意每個服務都必須通過 image 指令指定鏡像或者用build
指令指定 Dockerfile 來自動構建生成鏡像,這里使用第一種。 -
networks
,配置容器連接的網絡,文件最后的 networks 則是先創建網絡 -
image
,指定服務的鏡像 -
container_name
,指定容器名,默認使用項目名稱_服務名稱_序號
的格式 -
ports
,配置端口映射 -
volumes
,將容器數據掛載到宿主機。如果使用數據卷方式則需要先創建數據卷,例如文件最后的 volumes;或者直接掛載到宿主機的指定目錄 -
depends_on
,設置服務間的依賴關系,被依賴的 -
command
,覆蓋容器啟動后默認執行的命令 -
environment
,配置容器內的環境變量
docker_test 服務對應的 Dockerfile 鏡像構建文件:
FROM java:8
VOLUME /tmp # 定義匿名數據卷,SpringBoot使用的內嵌Tomcat容器默認將/tmp作為工作目錄
COPY docker_test-1.0-SNAPSHOT.jar /docker_test.jar
ENTRYPOINT ["java", "-jar", "docker_test.jar"]
EXPOSE 7001
構建鏡像:
docker build Dockerfile -t docker_test:v1 .
Compose 命令
https://docs.docker.com/compose/reference/
Compose 的大部分命令操作的對象既可以是項目本身,也可以指定為項目中的服務,如果沒有特別指定則命令操作的對象將是項目,也就是項目中所有的服務都會受到命令影響。命令的基本格式如下:
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
-
-f
,指定 Compose 文件名,默認的文件名為docker-compose.yml
-
-p
,指定項目名,默認為所在目錄名稱
以下是一些常用的命令,一般在模板文件目錄下執行:
-
docker-compose config
,驗證 Compose 文件格式是否正確 -
docker-compose up [OPTIONS] [SERVICE...]
,這個命令很重要,可以完成構建鏡像,創建、啟動服務容器,并關聯服務相關容器等一系列操作。默認情況,docker compose up
啟動的容器都在前臺運行,同時如果服務容器已經存在,它將會嘗試停止容器,然后重新創建。OPTIONS 常用參數:-
-d
,在后臺運行服務容器。 -
--no-deps
,重新部署指定服務 -
--force-recreate
,強制重新創建容器 -
--no-recreate
,如果容器已經存在了,則不重新創建;不能和 --force-recreate 同時使用。
-
-
docker-compose ps
,列出項目中的容器 -
docker-compose restart [SERVICE...]
,重啟項目中的容器,不指定服務名則重啟全部 -
docker-compose stop [SERVICE...]
,停止運行的容器 -
docker-compose exec [SERVICE] sh
,進入指定容器 -
docker-compose logs [-f] [SERVICE]
,查看容器的日志