Docker 开发随笔

Docker 删除所有 none 镜像

1
# docker rmi `docker images | grep  '<none>' | awk '{print $3}'`

Docker 构建镜像时忽略错误信息

根据 Dockerfile 构建镜像,当构建失败时,往往会出现以下错误:

1
2
automake: error: no 'Makefile.am' found for any configure output
Error build: The command [/bin/sh -c aclocal && autoconf && automake -a] returned a non-zero code: 1

在很多企业的应用场景里,上面的错误信息实际上是无害的,可以忽略不处理。但一旦出现此类错误 Docker 就会停止构建,此时如果需要让 Docker 忽略类似的错误信息,可以使用 exit 0

1
RUN make

当 Dockerfile 里包含了上面类似的指令,则可以改写为以下的内容,这将始终返回 0(成功)退出代码,此时 Docker 不会意外终止构建过程

1
RUN make; exit 0

不同网段之间的容器实现互相通信

Docker 命令行的使用

提示

假设存在两个容器,分别是 Redis 容器(172.89.0.2)和 Nginx 容器(172.64.0.5),两者具体的 docker-compose.yml 配置信息如下:

  • Redis 容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: '3.5'

services:
redis:
image: redis:5.0.4-stretch
container_name: redis
restart: always
privileged: false
environment:
TZ: 'Asia/Shanghai'
ports:
- 6379:6379
networks:
redis-network:
ipv4_address: 172.89.0.2
volumes:
- '/usr/local/redis/data:/data'
- '/usr/local/redis/redis.conf:/usr/local/etc/redis/redis.conf'
command: redis-server /usr/local/etc/redis/redis.conf

networks:
redis-network:
name: redis-network
driver: bridge
ipam:
config:
- subnet: 172.89.0.0/24
  • Nginx 容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
version: '3.5'

services:
nginx:
image: nginx:1.20
container_name: nginx
restart: always
privileged: false
environment:
TZ: 'Asia/Shanghai'
networks:
nginx-network:
ipv4_address: 172.64.0.5
ports:
- 80:80
- 443:443
volumes:
- '/usr/local/nginx/conf/nginx.conf:/usr/local/nginx/conf/nginx.conf'

networks:
nginx-network:
name: nginx-network
driver: bridge
ipam:
config:
- subnet: 172.64.0.0/24

上述的 Redis 和 Nginx 容器分别处于不同的网段中,两者之间的网络无法直接 Ping 得通;若希望在 Redis 内可以 Ping 通 Nginx 容器,那么可以将 Nginx 容器添加到 Redis 容器所在网络里,命令示例如下:

1
2
3
4
5
6
7
8
# 将Nginx容器添加到Redis容器所在网络里
# docker network connect redis-network nginx

# 查看Nginx容器在Redis容器所在网络里的IP
# docker network inspect redis-network

# 在Redis容器内直接Ping通Nginx容器(这里的IP是Nginx容器在新网络里的IP地址)
# ping 172.89.0.3

警告

使用 docker network connect redis-network nginx 命令,将 Nginx 容器添加到 Redis 容器所在网络后,Nginx 在新网络里的 IP 地址是不固定的,例如 Docker 服务重启后 IP 地址会变更,这一点必须注意!


将 Nginx 容器从 Redis 容器所在网络里移除掉,可以使用以下命令:

1
# docker network disconnect redis-network nginx

提示

Docker 默认网络的名称是 bridge,默认情况下创建的所有容器都会在 bridge 网络内。

1
2
3
4
5
# 查看Docker的所有网络
# docker network ls

# 查看某网络下所有容器的信息(包括各个容器的IP)
# docker network inspect redis-network

Docker-Compose 的使用

在 Docker-Compose 中,支持将 Nginx 容器添加到 Redis 容器所在网络里,配置示例如下所示。

提示

值得一提的是,这里通过 docker-compose.yml 配置文件,将 Nginx 容器添加到 Redis 容器所在网络后,Nginx 在新网络里的 IP 地址是固定的。

  • Redis 容器,配置内容和上面的案例一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: '3.5'

services:
redis:
image: redis:5.0.4-stretch
container_name: redis
restart: always
privileged: false
environment:
TZ: 'Asia/Shanghai'
ports:
- 6379:6379
networks:
redis-network:
ipv4_address: 172.89.0.2
volumes:
- '/usr/local/redis/data:/data'
- '/usr/local/redis/redis.conf:/usr/local/etc/redis/redis.conf'
command: redis-server /usr/local/etc/redis/redis.conf

networks:
redis-network:
name: redis-network
driver: bridge
ipam:
config:
- subnet: 172.89.0.0/24
  • Nginx 容器,配置了多个网络,同时指定了容器在不同网络下的 IP 地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
version: '3.5'

services:
nginx:
image: nginx:1.20
container_name: nginx
restart: always
privileged: false
environment:
TZ: 'Asia/Shanghai'
networks:
nginx-network:
ipv4_address: 172.64.0.5
redis-network:
ipv4_address: 172.89.0.3
ports:
- 80:80
- 443:443
volumes:
- '/usr/local/nginx/conf/nginx.conf:/usr/local/nginx/conf/nginx.conf'

networks:
nginx-network:
name: nginx-network
driver: bridge
ipam:
config:
- subnet: 172.64.0.0/24
redis-network:
name: redis-network
driver: bridge
ipam:
config:
- subnet: 172.89.0.0/24
  • 查看 Docker 的网络状况
1
2
3
4
5
# 查看Nginx容器在Redis容器所在网络里的IP
# docker network inspect redis-network

# 在Redis容器内直接Ping通Nginx容器
# ping 172.89.0.3

Docker 升级版本后无法启动

Docker 升级版本后无法正常启动,使用命令 journalctl -u docker 查看系统日志信息,得到的错误信息如下:

1
[graphdriver] prior storage driver devicemapper is deprecated and will be removed in a future release; update the the daemon configuration and explicitly choose this storage driver to continue using it;

创建或编辑 /etc/docker/daemon.json 配置文件,然后在配置文件内添加以下内容:

1
2
3
{
"storage-driver": "devicemapper"
}

再次重启 Docker 服务

1
systemctl restart docker

Docker 查看容器的资源占用情况

使用以下命令,可以查看 Docker 容器的 CPU、内存、网络资源占用情况。

1
2
3
4
5
# 查看所有容器
# docker stats

# 查看特定的容器
# docker stats mysql

Docker 容器添加自定义 Hosts

为了向容器的 /etc/hosts 配置文件中添加一些记录,可以使用以下任意一种方式来实现。

  • Docker 启动容器时,添加 Hosts
1
docker run --add-host=myhostname:10.180.8.1 --name test -it debian
  • Docker-Compose 通过配置参数 extra_hosts 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: "3.5"

services:
pms:
image: idoop/zentao:latest
container_name: pms
privileged: false
ports:
- 8080:80
- 3386:3306
environment:
- ADMINER_USER=root
- ADMINER_PASSWD=123456
- BIND_ADDRESS=false
- SET_CONTAINER_TIMEZONE=true
- CONTAINER_TIMEZONE=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
- /data/pms/:/opt/zbox/
restart: always
extra_hosts:
- "github.com:140.82.112.4"
- "smtp.exmail.qq.com:113.96.208.92"
  • Docker-Compose 的另一种写法,可能需要高版本的 Compose 才支持(例如 1.3 版本)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: "3.5"

services:
pms:
image: idoop/zentao:latest
container_name: pms
privileged: false
ports:
- 8080:80
- 3386:3306
environment:
- ADMINER_USER=root
- ADMINER_PASSWD=123456
- BIND_ADDRESS=false
- SET_CONTAINER_TIMEZONE=true
- CONTAINER_TIMEZONE=Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
- /data/pms/:/opt/zbox/
restart: always
extra_hosts:
- github.com: 140.82.112.4
- smtp.exmail.qq.com: 113.96.208.92

Docker 数据卷占用大量磁盘空间

特别注意

在下述的清理过程中,请小心操作,特别是在删除卷和容器时,确保它们不再被需要。

偶然发现 /var/lib/docker/volumes 目录占用大量磁盘空间,通常是因为 Docker 容器产生的持久化数据未被正确清理。这里有几种解决方法来清理不再需要的 Docker 卷和释放磁盘空间:

查看未使用的卷

Docker 提供了命令来列出当前系统中的所有卷,可以使用以下命令查看未使用的卷:

1
docker volume ls -f dangling=true

此命令将列出 “悬空”(未使用)的卷。这些卷通常是因为相关容器已经删除,但卷没有被清理。

删除未使用的卷

可以通过以下命令删除所有未使用的卷:

1
docker volume prune

这将删除所有未使用的 Docker 卷,系统会要求确认操作。

手动删除指定的卷

如果想手动删除特定的卷,可以使用以下命令:

1
docker volume rm <volume_name>

可以从 docker volume ls 的输出中找到卷的具体名称。

清理未使用的容器、镜像和网络

有时候不只是卷占用空间,未使用的容器、镜像和网络也会占用大量空间。可以运行以下命令清理它们:

1
docker system prune -a

该命令将删除所有未使用的容器、镜像、卷和网络。加上 -a 选项后,它还会删除没有被任何容器使用的未标记镜像。

检查卷的具体占用空间

如果想检查具体哪些卷占用了大量空间,可以使用以下命令查看每个卷的大小:

1
docker system df -v

这会显示 Docker 使用的磁盘空间,包括容器、卷、镜像和构建缓存的详细信息。

Docker 设置代理加速镜像下载

  • 创建或者编辑 http-proxy.conf 配置文件,并添加如下内容:
1
2
3
4
5
# 创建配置目录
sudo mkdir -p /etc/systemd/system/docker.service.d

# 创建配置文件
sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf
1
2
3
4
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:6800"
Environment="HTTPS_PROXY=http://127.0.0.1:6800"
Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com"

如果代理需要用户名和密码,可以使用以下格式的内容:

1
2
3
4
[Service]
Environment="HTTP_PROXY=http://username:password@127.0.0.1:6800"
Environment="HTTPS_PROXY=http://username:password@127.0.0.1:6800"
Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com"
  • 重启 Docker 服务使配置生效
1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

特别注意

这里不能在 Linux 终端中配置代理来让 Docker 走代理,比如 export https_proxy=http://127.0.0.1:6800。因为 Docker 守护进程作为一个后台服务运行,它并不会读取或继承用户的 Shell 环境变量(除非在启动时特别指定)。为了确保 Docker 在拉取镜像或进行其他网络通讯时能够走代理服务器,必须在 Docker 的服务配置中设置这些代理变量。更多介绍请看 这里