Docker 实践
Docker 实践
Docker 视频教程正在制作中。。。
当前进度 5%,敬请关注。
一、安装 Docker
1.1 Ubuntu 中安装
删除旧版本
$ for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
设置Docker源
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
安装Docker
# 安装最新版本
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 安装指定版本
# List the available versions:
apt-cache madison docker-ce | awk '{ print $3 }'
5:24.0.0-1~ubuntu.22.04~jammy
5:23.0.6-1~ubuntu.22.04~jammy
...
VERSION_STRING=5:24.0.0-1~ubuntu.22.04~jammy
sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin
验证安装
$ sudo docker run hello-world
替换国内软件源
# 查看当前是否有镜像源配置,如果有输出把服务文件中的--registry-mirror删掉
$ systemctl cat docker | grep '\-\-registry\-mirror'
# 编辑docker配置文件加入一下内容
$ vim /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirror.baidubce.com"
"https://ccr.ccs.tencentyun.com"
]
}
# 重启服务
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
# 查看docker信息
$ docker info
# 测试源镜像
docker pull mirror.baidubce.com/library/nginx:latest
docker pull ccr.ccs.tencentyun.com/library/nginx:latest
1.2 CentOS 中安装
# 安装Docker
sudo yum remove docker\*
sudo yum install -y yum-utils
#配置docker的yum地址
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#安装指定版本
sudo yum install -y docker-ce-20.10.7 docker-ce-cli-20.10.7 containerd.io-1.4.6
#yum install -y docker-ce docker-ce-cli containerd.io
# 启动&开机启动docker
systemctl enable docker --now
# docker加速配置
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://5j8ttgd9.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
# 修改docker Cgroup Driver为systemd 上面配置已经修改
#sed -i.bak "s#^ExecStart=/usr/bin/dockerd.*#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd#g" /usr/lib/systemd/system/docker.service
1.3 Debian 中安装
移除旧软件
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
设置软件源
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
安装docker
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
替换国内软件源
# 查看当前是否有镜像源配置,如果有输出把服务文件中的--registry-mirror删掉
$ systemctl cat docker | grep '\-\-registry\-mirror'
# 编辑docker配置文件加入一下内容
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://mirror.baidubce.com"
,"https://ccr.ccs.tencentyun.com"
,"https://5j8ttgd9.mirror.aliyuncs.com"
]
}
EOF
# 重启服务
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
# 查看docker信息
$ docker info
# 测试源镜像
docker pull mirror.baidubce.com/library/nginx:latest
docker pull ccr.ccs.tencentyun.com/library/nginx:latest
docker pull 5j8ttgd9.mirror.aliyuncs.com/library/nginx:latest
验证安装
$ sudo docker run hello-world
让其他用户访问docker
sudo usermod -aG docker tpxcer
sudo reboot
卸载 Docker
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
二、镜像相关命令
2.1 获取镜像
Docker Hub 上有大量的高质量的镜像可以用。从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
- Docker 镜像仓库地址:地址的格式一般是
<域名/IP>[:端口号]
。默认地址是 Docker Hub。 - 仓库名:如之前所说,这里的仓库名是两段式名称,即
<用户名>/<软件名>
。对于 Docker Hub,如果不给出用户名,则默认为library
,也就是官方镜像。
示例:
docker pull ubuntu:18.04
docker pull nginx
2.2 列出镜像
列出已经下载下来的镜像
docker image ls
查看镜像、容器、数据卷所占用的空间 docker system df
列出特定的某个镜像 docker image ls ubuntu:18.04
看到在 mongo:3.2
之后建立的镜像 docker image ls -f since=mongo:3.2
想查看某个位置之前的镜像也可以,只需要把 since
换成 before
即可。
此外,如果镜像构建时,定义了 LABEL
,还可以通过 LABEL 来过滤。
$ docker image ls -f label=com.example.version=0.1
直接列出镜像结果,并且只包含镜像ID和仓库名
$ docker image ls --format "{{.ID}}: {{.Repository}}"
查看容器的存储层变动
docker diff
查看镜像内的历史记录
docker history nginx:v2
2.3 删除镜像
# 语法
docker image rm [选项] <镜像1> [<镜像2> ...]
# 删除虚悬镜像
docker image prune
docker image prune --force --all
# 删除所有镜像
docker image rm $(docker image ls --format "{{.ID}}")
# 删除所有仓库名为 redis 的镜像
docker image rm $(docker image ls -q redis)
# 或者删除所有在 mongo:3.2 之前的镜像
docker image rm $(docker image ls -q -f before=mongo:3.2)
2.4 创建镜像
例子1
# docker文件
vim nginx-Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
# 制作镜像
# 注意,最后一个点是 docker 的打包目录, docker 将该目录下所有的文件都打包进镜像。
docker build -t nginx:v3 -f nginx-Dockerfile .
例子2
# 镜像文件
MAC-➜ ckad git:(master) vim dockerfile/Dockerfile
FROM centos:7
MAINTAINER Sander <mail@example.com>
# Add repo file
ADD ./sander.repo /etc/yum.repos.d/
# Install cool software
RUN yum --assumeyes update && \
yum --assumeyes install bash nmap iproute && \
yum clean all
ENTRYPOINT ["/usr/bin/nmap"]
CMD ["-sn", "172.17.0.0/24"]
# 创建镜像
MAC-➜ ckad git:(master) cd dockerfile
MAC-➜ dockerfile git:(master) docker build -t nmap . --no-cache
例子3
# 配置文件
[root@docker autoscaling]# cat Dockerfile
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
# 制作镜像
[root@docker autoscaling]# docker build -t php-apache .
Sending build context to Docker daemon 4.608kB
Step 1/3 : FROM php:5-apache
5-apache: Pulling from library/php
Digest: sha256:0a40fd273961b99d8afe69a61a68c73c04bc0caa9de384d3b2dd9e7986eec86d
Status: Downloaded newer image for php:5-apache
---> 24c791995c1e
Step 2/3 : COPY index.php /var/www/html/index.php
---> 0bb1883baf4c
Step 3/3 : RUN chmod a+rx index.php
---> Running in 40948bf4b920
Removing intermediate container 40948bf4b920
---> 2806066056d2
Successfully built 2806066056d2
Successfully tagged php-apache:latest
2.5 使用comment创建镜像
# 创建一个文件
[root@docker ~]# docker exec -it dice-server sh
sh-4.4# echo hello > /tmp/hellofile
sh-4.4# ls -l /tmp/hellofile
-rw-r--r--. 1 root root 6 Oct 23 16:40 /tmp/hellofile
sh-4.4# exit
exit
# 查看差异
[root@docker ~]# docker diff dice-server | grep -i hello
A /tmp/hellofile
# 提交更改
[root@docker ~]# docker commit dice-server dice-server
sha256:a2237f881e326aabaac9eb815ba988e21e1fa91481c392a7e896fe63f0c571f3
# 查看镜像可以看到才创建了19秒
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dice-server latest a2237f881e32 19 seconds ago 546MB
# 把镜像保存成文件
[root@docker ~]# docker save -o dice-server.tar dice-server
[root@docker ~]# ll -h
总用量 525M
-rw-------. 1 root root 525M 10月 23 16:46 dice-server.tar
2.6 查看镜像变更历史
OMV-➜ ~ docker image history lscr.io/linuxserver/qbittorrent:latest
IMAGE CREATED CREATED BY SIZE COMMENT
80b60b9f5da8 8 days ago VOLUME [/config] 0B buildkit.dockerfile.v0
<missing> 8 days ago EXPOSE map[6881/tcp:{} 6881/udp:{} 8080/tcp:… 0B buildkit.dockerfile.v0
<missing> 8 days ago COPY /usr/bin/unrar-alpine /usr/bin/unrar # … 552kB buildkit.dockerfile.v0
<missing> 8 days ago COPY root/ / # buildkit 1.6kB buildkit.dockerfile.v0
<missing> 8 days ago RUN |4 BUILD_DATE=2023-10-15T06:52:25+00:00 … 177MB buildkit.dockerfile.v0
<missing> 8 days ago ENV HOME=/config XDG_CONFIG_HOME=/config XDG… 0B buildkit.dockerfile.v0
<missing> 8 days ago LABEL maintainer=thespad 0B buildkit.dockerfile.v0
2.7 镜像传输(镜像备份加载)
# 将镜像保存成压缩包
docker save -o abc.tar guignginx:v1.0
# 别的机器加载这个镜像
docker load -i abc.tar
2.8 推送远程仓库
推送镜像到docker hub;应用市场
docker tag local-image:tagname new-repo:tagname
docker push new-repo:tagname
# 把旧镜像的名字,改成仓库要求的新版名字
[root@docker ~]# docker tag php-apache:latest tpxcer/php-apache:latest
# 登录到docker hub
[root@docker ~]# docker login
# 推送
[root@docker ~]# docker push tpxcer/php-apache:latest
# 推送完成镜像后退出
docker logout
# 别的机器下载
docker pull leifengyang/guignginx:v1.0
2.9 其他命令
# 查看镜像支持的环境变量
docker run IMAGE env
三、容器相关命令
3.-1 启动容器例子
# 运行一个hello-world镜像的应用
# docker run [options] image[:tag] [command] [arg...]
docker run hello-world
# [command] 例子
tpxcer@docker-dev:~$ sudo docker run busybox echo "hello world!"
# 后台运行 -d
docker run -d nginx
# 设定容器的名字 --name
docker run -d nginx --name nginx
# 设置重启策略
# --restart
# no:不重启
# on-failure:如果容器出错(比如非零退出)重启
# always:总是重启,docker服务器启动的时候也重启
# unless-stopped:永远重启,除非被手动停止了
docker run -d --name nginx --restart no nginx
# 端口映射
# -p<host port>:<container port>
docker run -d --name nginx --restart unless-stopped -p 8080:80 nginx
# 退出自动删除容器 不可与--restart共用
# --rm
docker run -d --name nginx --rm -p 8080:80 nginx
# 内存限制
# --memory
docker run -d --name nginx --rm --memory 500M -p 8080:80 nginx
# 内存限制
# --memory
docker run -d --name nginx --rm --memory 500M -p 8080:80 nginx
# 设置内存保留
# 内存保留是指为容器分配的最小内存量,即使系统内存紧张时,也会为容器保留该内存。
# --memory-reservation
docker run -d --name nginx --rm --memory 500M --memory-reservation 256M -p 8080:80 nginx
3.0 创建容器
[root@docker ~]# docker create -it --name=busybox busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
5cc84ad355aa: Pull complete
Digest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
Status: Downloaded newer image for busybox:latest
09d0c1ee52e1af38d8015fd0cf96cff1be12997b440879d367e3f2da0539816d
[root@docker ~]# docker ps -a |grep busybox
09d0c1ee52e1 busybox "sh" About a minute ago Created
3.1 启动容器
- 启动创建好的容器
# 接上个步骤
[root@docker ~]# docker start busybox
busybox
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09d0c1ee52e1 busybox "sh" 3 minutes ago Up 10 seconds busybox
- 运行ubuntu容器
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:18.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。
$ docker run -it --rm \
ubuntu:18.04 \
bash
docker run
就是运行容器的命令,具体格式我们会在 容器 一节进行详细讲解,我们这里简要的说明一下上面用到的参数。
-it
:这是两个参数,一个是-i
:交互式操作,一个是-t
终端。我们这里打算进入 `bash`` 执行一些命令并查看返回结果,因此我们需要交互式终端。--rm
:这个参数是说容器退出后随之将其删除。ubuntu:18.04
:这是指用ubuntu:18.04
镜像为基础来启动容器。bash
:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是bash
。
- 启动nginx应用容器
# 启动nginx应用容器,并映射88端口,测试的访问
# -d:后台运行
# --restart=always: 开机自启
docker run --name=mynginx -d --restart=always -p 88:80 nginx
3.2 设置应用开机自启
docker update 容器id/名字 --restart=always
3.3 挂载数据到外部修改
docker run --name=mynginx \
-d --restart=always \
-p 88:80 -v /data/html:/usr/share/nginx/html:ro \
nginx
# 修改页面只需要去 主机的 /data/html
3.4 查看容器
# 查看正在运行的容器
docker ps
# 查看所有容器
docker ps -a
# 如何获取某个容器的 PID 信息
docker inspect --format '{{ .State.Pid }}' <CONTAINER ID or NAME>
何获取某个容器的 IP 地址
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <CONTAINER ID or NAME>
# 列出所有容器ID
docker ps -aq
3.5 交互方式访问运行中的容器
docker exec -it CONTAINER bash
3.6 停止容器
docker stop 容器名
# 停止所有正在运行的容器
docker stop $(docker container ls -q)
3.7 删除容器
# 删除所有容器
docker rm $(docker ps -aq)
docker container rm 容器名
# 批量清理已经停止的容器
docker container prune
docker container prune -f
# 删除 exited 状态容器
docker rm $(docker ps --all -q -f status=exited)
3.8 容器网络设定
# 给容器指定一个固定 IP 地址,而不是每次重启容器 IP 地址都会变
$ docker network create -d bridge --subnet 172.25.0.0/16 my-net
$ docker run --network=my-net --ip=172.25.3.3 -itd --name=my-container busybox
# 临时退出一个正在交互的容器的终端,而不终止它
按 Ctrl-p Ctrl-q。如果按 Ctrl-c 往往会让容器内应用进程终止,进而会终止容器。
3.9 删除网络
docker network ls
docker network rm my_network
3.10 查看容器日志
docker logs 容器名/id
3.11 把容器指定位置的东西复制
#把容器指定位置的东西复制出来
docker cp 5eff66eec7e1:/etc/nginx/nginx.conf /data/conf/nginx.conf
#把外面的内容复制到容器里面
docker cp /data/conf/nginx.conf 5eff66eec7e1:/etc/nginx/nginx.conf
3.12 重启容器
docker restart 容器名
3.13 迁移容器
# 执行导出命令
docker export busybox > busybox.tar
# 导入容器命令格式
docker import [OPTIONS] file | URL [REPOSITORY[:TAG]]
3.13 查看容器资源使用情况
docker stats qbittorrent
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
42fd2ad56ff6 qbittorrent 15.73% 7.731GiB / 15.63GiB 49.46% 22.3GB / 261GB 636MB / 536MB 26
四、DockerFile
dockerfile 是 Docker 用来构建镜像的文本文件,包含自定义的指令和格式,可以通过 build 命令从 dockerfile 中构建镜像,命令格式为:docker build [OPTIONS] PATH | URL | -
。
dockerfile 描述了组装镜像的步骤,其中每条指令都是单独执行的。除了 FROM 指令,其他的每一条指令都会在上一条指令所生成镜像的基础上执行,执行完后会生成一个新的镜像层,新镜像层覆盖在原来的镜像之上从而形成新的镜像。为了提高镜像构建的速度, Docker Daemon 会缓存构建过程中的中间镜像。在构建镜像时,它会将 dockerfile 中下一条指令和基础镜像的所有子镜像做比较,如果有一个子镜像是由相同的指令生成的,则命中缓存,直接使用该镜像,而不用再生成一个新的镜像。常用指令如下:
4.1 FROM
FROM 指令用于指定基础镜像,因此所有的 dockerfile 都必须使用 FROM 指令开头。FROM 指令可以出现多次,这样会构建多个镜像,每个镜像创建完成后,Docker 命令行界面会输出该镜像的 ID。常用指令格式为:FROM <image>[:<tag>] [AS <name>]
。
4.2 MAINTAINER
MAINTAINER 指令可以用来设置作者名称和邮箱,目前 MAINTAINER 指令被标识为废弃,官方推荐使用 LABEL 代替。
4.3 LABEL
LABEL 指令可以用于指定镜像相关的元数据信息。格式为:LABEL <key>=<value> <key>=<value> <key>=<value> ...
。
4.4 ENV
ENV 指令用于声明环境变量,声明好的环境变量可以在后面的指令中引用,引用格式为 $variable_name
或 ${variable_name}
。常用格式有以下两种:
ENV <key> <value>
:用于设置单个环境变量;ENV <key>=<value> ...
:用于一次设置多个环境变量。
ENV NGINX_VERSION 1.14.0-0ubuntu1.3
4.5 EXPOSE
EXPOSE 用于指明容器对外暴露的端口号,格式为:EXPOSE <port> [<port>/<protocol>...]
,您可以指定端口是侦听 TCP 还是 UDP,如果未指定协议,则默认为 TCP。
EXPOSE 80
4.6 WORKDIR
WORKDIR 用于指明工作目录,它可以多次使用。如果指明的是相对路径,则它将相对于上一个WORKDIR指令的路径。示例如下:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd # 此时pwd为:/a/b/c
4.7 COPY
COPY 指令的常用格式为:COPY <src>... <dest>
,用于将指定路径中的文件添加到新的镜像中,拷贝的目标路径可以不存在,程序会自动创建。
COPY index.html ./
4.8 ADD
ADD 指令的常用格式为:COPY <src>... <dest>
,作用与 COPY 指令类似,但功能更为强大,例如 Src
支持文件的网络地址,且如果 Src
指向的是压缩文件,ADD 在复制完成后还会自动进行解压。
COPY index.html ./
4.9 RUN
RUN 指令会在前一条命令创建出的镜像基础上再创建一个容器,并在容器中运行命令,在命令结束后提交该容器为新的镜像。它支持以下两种格式:
RUN <command>
(shell 格式)RUN ["executable", "param1", "param2"]
(exec 格式)
使用 shell 格式时候,命令通过 /bin/sh -c
运行,而当使用 exec 格式时,命令是直接运行的,容器不调用 shell 程序,这意味着不会发生正常的 shell 处理。例如,RUN ["echo","$HOME"]
不会对 $HOME
执行变量替换,此时正确的格式应为:RUN ["sh","-c","echo $HOME"]
。下面的 CMD 指令也存在同样的问题。
RUN apt-get update && apt-get install -y curl
# 这里引用ENV创建的环境变量
RUN apt-get update && apt-get install -y nginx=$NGINX_VERSION
4.10 CMD
CMD ["executable","param1","param2"]
(exec 格式, 首选)CMD ["param1","param2"]
(作为 ENTRYPOINT 的默认参数)CMD command param1 param2
(shell 格式)
CMD 指令提供容器运行时的默认值,这些默认值可以是一条指令,也可以是一些参数。一个 dockerfile 中可以有多条 CMD 指令,但只有最后一条 CMD 指令有效。CMD 指令与 RUN 指令的命令格式相同,但作用不同:RUN 指令是在镜像的构建阶段用于产生新的镜像;而 CMD 指令则是在容器的启动阶段默认将 CMD 指令作为第一条执行的命令,如果用户在 docker run 时指定了新的命令参数,则会覆盖 CMD 指令中的命令。
CMD ["nginx","-g","daemon off;"]
4.11 ENTRYPOINT
ENTRYPOINT 指令 支持以下两种格式:
ENTRYPOINT ["executable", "param1", "param2"]
(exec 格式,首先)ENTRYPOINT command param1 param2
(shell 格式)
ENTRYPOINT 指令 和 CMD 指令类似,都可以让容器在每次启动时执行相同的命令。但不同的是 CMD 后面可以是参数也可以是命令,而 ENTRYPOINT 只能是命令;另外 docker run 命令提供的运行参数可以覆盖 CMD,但不能覆盖 ENTRYPOINT ,这意味着 ENTRYPOINT 指令上的命令一定会被执行。如下 dockerfile 片段:
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
当执行 docker run -it image
后,此时输出为 hello world
,而当你执行 docker run -it image spring
,此时 CMD 中的参数会被覆盖,此时输出为hello spring
。
4.12 STOPSIGNAL
STOPSIGNAL指令用于设置将发送到容器以优雅停止的系统调用信号。当Docker容器接收到指定的信号时,它将尝试停止容器中运行的进程,然后再关闭容器。
这里,信号是Docker在需要停止容器时将发送到容器的信号。可以将信号指定为整数或作为信号名称。例如,你可以使用SIGTERM或SIGINT作为信号。以下是一些常见的信号:
- SIGTERM(默认):优雅地请求进程终止。
- SIGINT:类似于SIGTERM,通常由CTRL+C触发。
- SIGKILL:立即终止进程,不允许进程进行清理工作。
STOPSIGNAL SIGINT
4.13 HEALTHCHECK
HEALTHCHECK 指令在 Docker 中用于告诉 Docker 如何测试容器以检查其是否仍在运行。它允许您定义一个命令,该命令将定期在容器内执行,以验证其健康状态。这对于自动检测和处理容器可能无响应或功能不正常的情况非常有用。
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl -f http://localhost/ || exit 1
五、docker-compose
# 启动 docker
docker-compose up
# 停止 docker
docker-compose down
# 启动 docker 并在后台运行
docker-compose up -d
# 重编译 docker 并运行
docker-compose up --build
备份数据库
docker exec CONTAINER /usr/bin/mysqldump -u root --password=root DATABASE > backup.sql
恢复数据库
cat backup.sql | docker exec -i CONTAINER /usr/bin/mysql -u root --password=root DATABASE
六、创建自己的应用镜像
6.1 编写自己的应用
写一个小应用操作redis,代码:code/java/docker
6.2 Dockerfile
code/java/docker/Dockerfile
FROM openjdk:8-jdk-slim
LABEL maintainer=txpcer
COPY target/*.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
6.3 构建镜像
docker build -t java-demo:v1.0 -f Dockerfile .
6.4 (测试)启动容器
docker run -d p 8080:8080 java-demo:v1.0
6.5 推送远程仓库
6.6 部署中间件
部署一个Redis+应用,尝试应用操作Redis产生数据
在宿主机创建一个redis的配置文件
vim /data/redis/redis.conf
appendonly yes
requirepass bihell
启动redis
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
#redis使用自定义配置文件启动
docker run -v /data/redis/redis.conf:/etc/redis/redis.conf \
-v /data/redis/data:/data \
-d --name myredis \
-p 6379:6379 \
redis:latest redis-server /etc/redis/redis.conf
七、存储
7.1 查看Storage Layers
# 查看容器
docker-dev➜ ~ sudo docker container inspect storage_nginx
# 可以看到GraphDriver部分,就是我们用的存储设备
"GraphDriver": {
"Data": {
"DeviceId": "79",
"DeviceName": "docker-254:0-787965-f630108512327e8793d405c01aaabbef139173980502bc7f80e4d63c1cab600e",
"DeviceSize": "10737418240"
},
"Name": "devicemapper"
},
# 查看镜像
docker-dev➜ ~ sudo docker image inspect nginx
"GraphDriver": {
"Data": {
"DeviceId": "15",
"DeviceName": "docker-254:0-787965-cdc32c01f27144c422ccd6bb2252cc9625322743243999396e8c6184458f4528",
"DeviceSize": "10737418240"
},
"Name": "devicemapper"
},
7.2 设定日志设备
# 查看当前日志Driver
tpxcer@docker-dev:~$ sudo docker info |grep Logging
Logging Driver: json-file
# 修改Logging Driver
tpxcer@docker-dev:~$ sudo vi /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size":"15m"
}
}
# 单独设定某个容器使用的log
docker run --log-driver syslog nginx
docker run --log-driver json-file --log-opt max-size=50m nginx
7.3 挂在磁盘
# 新版本推荐--mount
# bind 类型: 使用主机文件系统的权限。如果主机文件系统的权限设置为只读,那么容器中的挂载路径也将是只读的。
# volume 类型: 具有自己的权限设置。你可以在创建卷时指定权限,不受主机文件系统的影响。
# tmpfs 类型: 适用于需要在容器中进行临时数据存储,这些数据在容器停止或删除时会被清除。
docker run --mount type=bind,source=/host/path,target=/container/path my_image
# 使用 -v 选项时,语法较为简单,只需提供源路径和目标路径
docker run -v /host/path:/container/path my_image
7.4 查看镜像的占用
# 简单查看
tpxcer@docker-no-proxy:~$ sudo docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 6 2.576GB 0B (0%)
Containers 6 6 220kB 0B (0%)
Local Volumes 2 1 15.57kB 6.027kB (38%)
Build Cache 0 0 0B 0B
# 详细查看
tpxcer@docker-no-proxy:~$ sudo docker system df -v
Images space usage:
REPOSITORY TAG IMAGE ID CREATED SIZE SHARED SIZE UNIQUE SIZE CONTAINERS
tpxcer/dice2-dice-openresty latest 6a3e06db8755 7 days ago 105MB 0B 104.6MB 1
tpxcer/dice2-dice-server latest 1870150cf915 7 days ago 547MB 0B 546.8MB 1
tpxcer/dice2-dice-front latest 5ac34e7eaaa3 8 days ago 1.09GB 0B 1.088GB 1
tpxcer/dice2-dice-mysql latest e60e18c88bdc 8 days ago 516MB 0B 515.7MB 1
lscr.io/linuxserver/qbittorrent latest aaa50cb1023b 8 days ago 205MB 0B 204.6MB 1
tpxcer/dice2-dice-redis latest c5afd8bd49ca 14 months ago 117MB 0B 116.9MB 1
Containers space usage:
CONTAINER ID IMAGE COMMAND LOCAL VOLUMES SIZE CREATED STATUS NAMES
c0e2114bd7cd lscr.io/linuxserver/qbittorrent:latest "/init" 0 23.9kB 22 hours ago Up 22 hours qbittorrent
3ad3c570fc36 tpxcer/dice2-dice-openresty:latest "/usr/local/openrest…" 0 162kB 2 days ago Up 2 days dice-openresty
4d02780445db tpxcer/dice2-dice-front:latest "/app/entrypoint.sh …" 0 1.59kB 2 days ago Up 2 days dice-front
14501e950ce0 tpxcer/dice2-dice-server:latest "java -jar dice.jar" 0 32.8kB 2 days ago Up 2 days dice-server
9be1b57df772 tpxcer/dice2-dice-redis:latest "docker-entrypoint.s…" 1 0B 2 days ago Up 2 days dice-redis
acc8a7e05215 tpxcer/dice2-dice-mysql:latest "docker-entrypoint.s…" 0 7B 2 days ago Up 2 days dice-mysql
Local Volumes space usage:
VOLUME NAME LINKS SIZE
d2300bfc8a688b10019a26b8be3032d8656dc4b6f6a0144a916bcd996eb52014 0 6.027kB
1576b996f0ea92fb55ece3764c6b4ab06567d3d6a58f17a1a93b928c8aa75aad 1 9.547kB
Build cache usage: 0B
CACHE ID CACHE TYPE SIZE CREATED LAST USED USAGE SHARED
# 将删除所有处于 <none> 状态的镜像
docker image prune
# 删除所有不再被任何容器使用的镜像,包括处于 <none> 状态的镜像以及被其他容器所使用的镜像。
docker image prune -a
八、网络
1. Host Network Driver
在Docker中,使用"Host Network Driver"意味着容器共享主机的网络命名空间。这使得容器能够直接访问主机上的网络栈,与主机上的进程具有相同的网络访问权限。与其他网络驱动相比,这种方式的容器不会在网络层面上被隔离,它们使用主机的网络栈,因此可以直接绑定到主机上的网络接口。
# --neme host 指定Host Network Driver
docker run -d --net host --name host_busybox radial/busyboxplus:curl sleep 3600
docker run -d --net host --name host_nginx nginx
# 本地网络 ip
docker-dev➜ ~ ip a |grep ens192
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
inet 192.168.50.179/24 brd 192.168.50.255 scope global dynamic ens192
# host_busybox ip
docker-dev➜ ~ sudo docker exec host_busybox ip a | grep ens192
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
inet 192.168.50.179/24 brd 192.168.50.255 scope global dynamic ens192
# 用host_busybox访问本地80端口
docker-dev➜ ~ sudo docker exec host_busybox curl localhost:80
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 255k 0 --:--:-- --:--:-- --:--:-- 600k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
2. Bridge Network Driver
Bridge Network Driver 是默认的网络驱动程序。它用于创建一个称为 "bridge" 的虚拟网络桥接,使得容器可以相互通信并与主机进行通信。每个使用 Bridge Network Driver 的容器都连接到这个虚拟桥接上。
一些关键的概念和特点包括:
- 虚拟网络桥接: Bridge Network Driver 创建了一个虚拟网络桥接,类似于物理交换机,用于连接运行在同一主机上的多个容器。
- 独立子网: 每个桥接网络都有自己的子网,并分配唯一的网段。容器通过桥接连接到这个子网,从而可以相互通信。
- 容器之间通信: 在同一桥接网络上的容器可以直接通过它们的 IP 地址相互通信,就像它们在同一本地网络上一样。
- 主机与容器通信: 桥接网络允许容器与主机进行通信,并且容器可以通过主机的 IP 地址访问外部网络
# 如果没有指定网络类型,那么会自动创建一个桥接网络,名字为docker0
docker-dev➜ ~ ip link |grep docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
# 创建一个桥接网络
docker network create --driver bridge my-bridge-net
# 如果在用ip link查看可以看到一个新的桥接网络
docker-dev➜ ~ ip link
7: br-e7d224a907b6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:23:2a:22:e0 brd ff:ff:ff:ff:ff:ff
# 新建nbridge_nginx和bridge_busybox容器,然后网络使用我们新建的桥接网络
docker run -d --name bridge_nginx --network my-bridge-net nginx
# bridge_nginx的80端口
docker run --rm --name bridge_busybox --network my-bridge-net radial/busyboxplus:curl curl bridge_nginx:80
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 342k 0 --:--:-- --:--:-- --:--:-- 600k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title
# 不写网络类型,默认创建的就是桥接网络
docker network create my-net
# 把my-net应用到容器
docker run -d --name my-net-busybox --network my-net radial/busyboxplus:curl sleep 3600
# 创建容器my-net-nginx ,注意没有指定--network参数,所以不会连接到 my-net 桥接网络
docker run -d --name my-net-nginx nginx
# 连接两个容器的网络
sudo docker network connect my-net my-net-nginx
# 使用 my-net-busybox 访问 my-net-nginx
docker-dev➜ ~ sudo docker exec my-net-busybox curl my-net-nginx:80
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 268k 0 --:--:-- --:--:-- --:--:-- 600k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
3. Overlay Network Driver
Overlay Network Driver 是 Docker 中一种用于跨多个主机连接容器的网络驱动程序。这个网络驱动程序允许在 Docker Swarm 模式下创建多主机的容器编排集群,并使得容器可以在不同主机之间通信。
4. MAC Virtual LAN Network Driver
MACVLAN(MAC Virtual LAN)是 Docker 中的一种网络驱动程序,允许容器直接连接到物理网络,而不是创建一个桥接网络。这使得容器可以在物理网络上拥有自己的 MAC 地址,并直接参与物理网络的通信。
- 直接连接到物理网络: MACVLAN 允许容器使用主机上的物理网络接口,并拥有自己唯一的 MAC 地址。每个容器看起来像是物理网络上的一个独立设备。
- 无需额外的地址转换: 与桥接网络相比,MACVLAN 不需要进行额外的地址转换(NAT),这可能导致性能损失。容器可以直接与物理网络上的其他设备进行通信。
- 容器之间通信: 在同一物理网络上的不同容器可以直接通过它们的 MAC 地址进行通信,就像它们是物理设备一样。
- IP 地址分配: 容器可以使用静态 IP 地址或通过 DHCP 从物理网络中获取 IP 地址。
# 创建网络
docker network create -d macvlan --subnet 192.168.0.0/24 --gateway 192.168.0.1 -o parent=ens192 my-macvlan-net
# 创建容器 macvlan_nginx
docker run -d --name macvlan_nginx --net my-macvlan-net nginx
# 创建容器 macvlan_busbox 然后访问 macvlan_nginx
docker-dev➜ ~ sudo docker run --rm --name macvlan_busbox --net my-macvlan-net radial/busyboxplus:curl curl 192.168.0.2:80
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 615 100 615 0 0 532k 0 --:--:-- --:--:-- --:--:-- 600k
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
5. None Network Driver
无网络
docker run --net none -d --name none_nginx nginx
6. Embedded DNS
网络别名
# 创建网络别名
docker run -d --name my-net-nginx2 --network my-net --network-alias my-nginx-alias nginx
# 现在以两个名字都可以访问单my-net-nginx容器
docker exec my-net-busybox curl my-net-nginx2:80
docker exec my-net-busybox curl my-nginx-alias:80
另一种别名姿势
# 创建容器
docker run -d --name my-net-nginx3 nginx
# 创建别名
docker network connect --alias another-alias my-net my-net-nginx3
# 访问
docker exec my-net-busybox curl another-alias:80
7. Managing Networks
# 网络列表
docker-dev➜ ~ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
0c9b75cdeb3e bridge bridge local
d51da9c09bd3 dashboard_default bridge local
# 查看某个网络
docker network inspect my-net
# 断开网络
docker network disconnect my-net my-net-nginx
# 删除网络
docker network rm my-net
8. Expose Port
映射端口
# 8080宿主机端口,80容器端口
docker run -d -p 8080:80 --name nginx_pub nginx
docker-dev➜ ~ curl localhost:8080
查看映射的端口
docker-dev➜ ~ sudo docker port nginx_pub
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080
- ExternalDNS
# 全局配置 外部dns设置
vim /etc/docker/daemon.json
{
"dns": ["8.8.8.8"]
}
# 单独配置
docker run --dns DNS_ADDRESS
九、安全
1. Docker Content Trust(DCT)
Docker Content Trust(DCT)是 Docker 中用于确保镜像的完整性和来源验证的一种安全特性。DCT 使用数字签名来验证镜像的发布者,并确保镜像在传输过程中没有被篡改。这有助于确保部署的镜像是由可信任的发布者创建的,有助于增强镜像的安全性。
DCT 的工作原理包括以下关键方面:
- 签名: Docker Content Trust 使用签名来确保镜像的完整性和来源。发布者使用自己的私钥对镜像进行签名,而用户可以使用发布者的公钥来验证签名。
- 签名的嵌入: 当镜像被推送到 Docker Registry 时,签名信息会与镜像一起存储。这样,下载镜像时,Docker 客户端会自动验证签名。
- 信任集(Trust Collection): Docker Content Trust 使用信任集来存储公钥信息。信任集是一个包含签名密钥的集合,由用户来管理。用户可以添加、移除或更新信任集中的公钥。
- 启用和禁用 DCT: DCT 是可选的,可以根据需要启用或禁用。如果 DCT 被禁用,Docker 将不会对拉取的镜像进行签名验证。
# 对镜像签名
# 创建trust key
docker-dev➜ ~ docker login
docker-dev➜ ~ docker trust key generate tpxcer
Generating key for tpxcer...
Enter passphrase for new tpxcer key with ID fbc0c74:
Repeat passphrase for new tpxcer key with ID fbc0c74:
Successfully generated and loaded private key. Corresponding public key available: /home/tpxcer/tpxcer.pub
# 增加签名者
docker-dev➜ ~ sudo docker trust signer add --key tpxcer.pub tpxcer tpxcer/dct-test
Adding signer "tpxcer" to tpxcer/dct-test...
Initializing signed repository for tpxcer/dct-test...
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID 65a7565:
Enter passphrase for new repository key with ID e7c8ea1:
Repeat passphrase for new repository key with ID e7c8ea1:
Successfully initialized "tpxcer/dct-test"
Successfully added signer: tpxcer to tpxcer/dct-test
# 创建测试镜像
docker-dev➜ ~ mkdir ~/dct-test
docker-dev➜ ~ cd dct-test
docker-dev➜ dct-test vi Dockerfile
FROM busybox:latest
CMD echo It worked!
# 编译镜像,不签名
docker-dev➜ dct-test sudo docker build -t tpxcer/dct-test:unsigned .
# 推送
docker-dev➜ dct-test sudo docker push tpxcer/dct-test:unsigned
The push refers to repository [docker.io/tpxcer/dct-test]
# 运行未签名的镜像
docker-dev➜ dct-test sudo docker run tpxcer/dct-test:unsigned
It worked!
# 启用 DCT,再次运行,未签名报错
docker-dev➜ dct-test sudo -i
root@docker-dev:~# export DOCKER_CONTENT_TRUST=1
root@docker-dev:~# docker run tpxcer/dct-test:unsigned
docker: No valid trust data for unsigned.
See 'docker run --help'.
# 编译镜像,签名
docker-dev➜ dct-test sudo docker build -t tpxcer/dct-test:signed .
# 签名并推送
docker-dev➜ ~ docker trust sign tpxcer/dct-test:signed
# 然后再执行
docker run tpxcer/dct-test:signed
2. 让其他用户访问docker
docker-dev➜ ~ sudo usermod -aG docker tpxcer
docker-dev➜ ~ sudo reboot
十、限制资源
# 限制内存
docker container run --name test2 --memory=100m -d popd 80:80 nginx
# 限制CPU
docker container run -d --cpus="1.5" -name test4 -p 70:70 nginx
docker container run -d --cpus="2" --cpuset-cpus="0,1" -name test -p 60:60 nginx