Docker
安装
按系统安装:
- Ubuntu:https://docs.docker.com/engine/install/ubuntu/
- Arch Linux:https://wiki.archlinux.org/title/Docker
需要安装:Docker + Docker Compose
Docker Compose
Ubuntu 20.04.4 LTS
1# 多用户安装 2mkdir -p /usr/local/lib/docker/cli-plugins 3sudo curl -SL https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-linux-x86_64 -o /usr/local/lib/docker/cli-plugins/docker-compose 4sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose 5docker compose version 6# Docker Compose version v2.2.3
一直在用 Arch Linux,和 Arch Linux 相比,在 Ubuntu 上安装 Docker Compose 要繁琐一点(当前用户):
1DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker} 2mkdir -p $DOCKER_CONFIG/cli-plugins 3curl -SL https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose 4chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose 5docker compose version 6# Docker Compose version 2.3.3 7sudo ln -s ~/.docker/cli-plugins/docker-compose /usr/bin/docker-compose 8echo 'alias docker-compose="docker compose"' >> ~/.bashrc
Arch
1sudo pacman -S docker-compose # so easy!
参考资料
配置
non-root 执行命令1
1sudo groupadd docker
2sudo usermod -aG docker $USER # 把 $USER 替换成当前用户
3## 登出再登陆,使更改生效。也可以运行以下命令激活改变
4newgrp docker
5## 验证可以没有 sudo 运行 docker
6docker run hello-world
开机启动 Docker2
1sudo systemctl enable docker.service
2sudo systemctl enable containerd.service
自定义 Docker 守护进程3
1# 开启 Docker 守护进程
2sudo systemctl start docker
通过修改 /etc/docker/daemon.json
文件进行自定义。这个文件能覆盖大部分 Docker 守护进程配置选项,不能通过它配置 HTTP 代理。
运行时目录和存储驱动:
1{
2 "data-root": "/mnt/docker-data",
3 "storage-driver": "overlay2"
4}
配置守护进程监听端口4:
有两种方式,一种通过 daemon.json
一种通过 systemd
。只介绍第一种。
一、在 /etc/docker/daemon.json
中设置 hosts
连接到 UNIX 套接字和 IP 地址。
1{
2 "hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]
3}
二、重启 Docker
三、通过 netstat
命令检查更改生效与否
1sudo netstat -lntp | grep dockerd
在重启 Docker 这一步出错,通过 sudo systemctl restart docker.service
无法重启。再次阅读文档后,发现第一种方式适合不使用 systemd 的发行版。我的 Arch Linux 使用 systemd,所以无法通过第一种方式配置。
如果想要尝试这一种配置方法, systemd 会不断出现 docker.service: Start request repeated too quickly.
错误。
第二种配置方式:
1sudo vim /usr/lib/systemd/system/docker.service
找到 ExecStart
并按以下方式修改:
1- ExecStart=/usr/bin/dockerd -H fd://
2+ ExecStart=/usr/bin/dockerd -H fd:// -H tcp://127.0.0.1:2375
重载 systemctl
配置,重启 Docker:
1sudo systemctl daemon-reload
2sudo systemctl restart docker.service
此时检查端口,发现可行:
1sudo netstat -lntp | grep dockerd
2# tcp 0 0 127.0.0.1:2375 0.0.0.0:* LISTEN 8823/dockerd
入门指南
什么是容器?
什么是容器镜像?
A container image represents binary data that encapsulates an application and all its software dependencies. Container images are executable software bundles that can run standalone and that make very well defined assumptions about their runtime environment.
– Kubernetes Documentation7
A container image is a static file with executable code that can create a container on a computing system. A container image is immutable—meaning it cannot be changed, and can be deployed consistently in any environment. It is a core component of a containerized architecture.
– Container Images: Architecture and Best Practices - Aqua8
镜像是二进制数据,它封装了应用运行所需的一切。
在运行镜像时,使用的是孤立系统,与主机隔离。
可以把容器视为 chroot
的扩展。文件系统来自镜像,但比 chroot
多了一层隔离。
什么是容器 volumes?
每次容器从镜像中构建时,都会是一个全新的开始,过去对旧有的容器做过的更改无法保存在新创建的容器上。当我们希望保存这些更改时,volumes 就出现了。它可以将容器的目标路径,挂载至主机系统中。当我们对当前容器中的文件进行修改时,这些修改会被保存至主机系统的特定 volume 中,即便当前容器被销毁,重新创建同样容器时,因为使用的还是之前的 volume,所以那些修改还在,也就达到了我们跨容器保存数据修改的目的。
volumes 有两种主要类型:named volumes 和 bind mounts。前者可以不必关心数据在主机的位置,但当我们想把主机的一些内容放到容器中时,named volumes 就无法达到目的。于是,bind mounts 就有了用武之地。它能把主机中的数据载入容器中,使得我们可以在容器中对数据进行操作。
多容器应用(TODO + MySQL)
一个容器是一个进程,最好只做一件事。
容器之间是互相隔离的,怎样才能通信呢?通过网络。 如果两个容器在相同网络环境下,它们便能互相通信;反之则不能。
以下是来自官方教程的命令(我修改了细节):
1# 创建网络
2docker network create todo-app
3# 在已创建的网络下,创建数据库todos,并创建网络别名mysql
4docker run -d \
5 --network todo-app --network-alias mysql \
6 -v todo-mysql-data:/var/lib/mysql \
7 -e MYSQL_ROOT_PASSWORD=secret \
8 -e MYSQL_DATABASE=todos \
9 mysql:8.0
10# 检查todos是否创建成功
11docker exec -it <mysql-container-id> mysql -u root -p
12mysql> SHOW DATABASES;
13 +--------------------+
14 | Database |
15 +--------------------+
16 | information_schema |
17 | mysql |
18 | performance_schema |
19 | sys |
20 | todos |
21 +--------------------+
22 5 rows in set (0.00 sec)
23# 使用nicolaka/netshoot提供的dig命令检查mysql是否和todo应用在同一网络
24docker run -it --network todo-app nicolaka/netshoot
25dig mysql
注意:不要在生产环境中使用环境变量,更安全的做法是使用 .env 之类的文件9。
使用 Docker Compose
在应用跟路径新建文件 docker-compose.yml
:
1version: "3.7"
2
3services:
4 app:
5 image: node:12-alpine
6 command: sh -c "yarn install && yarn run dev"
7 ports:
8 - 3000:3000
9 working_dir: /app
10 volumes:
11 - ./:/app
12 environment:
13 MYSQL_HOST: mysql
14 MYSQL_USER: root
15 MYSQL_PASSWORD: secret
16 MYSQL_DB: todos
17
18 mysql:
19 image: mysql:8.0
20 volumes:
21 - todo-mysql-data:/var/lib/mysql
22 environment:
23 MYSQL_ROOT_PASSWORD: secret
24 MYSQL_DATABASE: todos
25
26volumes:
27 todo-mysql-data:
确保之前运行的容器都已经停止。
在当前应用根路径下运行,启动容器:
1docker-compose up -d
查看日志:
1docker-compose logs -f
全部停止:
1docker-compose down # 该命令不删除创建的 volumes
2docker-compose down --volumes # 该命令删除创建的volumes
安全检查
1docker scan image_name
常用命令
1docker version # 输出Docker版本、系统等信息
2
3docker ps # 列出所有正在运行的容器
4docker ps -a # 列出所有容器
5docker build -t image_name . # 根据当前目录下的Dockerfile,构建镜像
6docker run -dp 3000:3000 image_name # 后台运行image_name,本地端口3000,容器内端口也是3000
7
8## 在对image内容进行修改后,需要再次运行 docker build 以更新构建
9docker stop container_name # 停止正在运行容器
10docker rm -f container_name # 移除正在运行容器
11docker rm container_name # 移除已停止容器
12
13## 发布自己的image
14docker push USER_NAME/image_name
15
16## 在容器内部执行命令
17docker exec <container-id> command
18
19## 管理镜像
20docker image
21docker image history image_name # 查看镜像层
22## 管理容器
23docker container
24
25## volume相关
26docker volume create volume_name # 创建一个 volume
27docker run -v volume_name:/container/path image_name # 连接 volume 至容器路径
28docker run -v "$(pwd):/container/path" image_name # 将主机所在的当前路径,放进容器的目标路径
分享一个比较冷门的 Dockerfile 的小技巧:
当你要安装一个 binary 工具时(比如 jq、yq、kubectl、helm、docker 等等),可以考虑直接从它们的镜像里 COPY 过来,替代使用 wget/curl 下载安装的方式,比如:
COPY –from=docker:20.10.12-dind-rootless /usr/local/bin/docker /usr/local/bin/docker
https://twitter.com/muzi_ii/status/1522599179918647296
— 参考资料
技巧
6 Docker Compose Best Practices for Dev and Prod
https://prod.releasehub.com/blog/6-docker-compose-best-practices-for-dev-and-prod
for Dev
- Mount Your Code as Volume to Avoid Unnecessary Rebuilds
- Use an Override File
- Use YAML Anchors
for Prod
- Leverage the Docker Restart Policy(updateconfig: true)
- Correct Cleanup Order of Docker Images(Do not use docker rm -f as it may destroy useful images. Always run docker rm -f –remove-orphans.)
- Setting Your Containers' CPU and Memory Limits
Tip: If you want to run multiple containers with different memory limits on the same machine, ensure that all your containers have different memory limits. This is because each container views how much memory it needs.
应用
- Watchtower 用于更新运行中的容器化应用
- Portainer 用于可视化操作容器应用
how to rm images
To remove Docker images that are not used by any containers, you can use the docker image prune
command. This command allows you to clean up unused images effectively. Here's how to do it:
Remove Dangling Images: By default,
docker image prune
will remove only dangling images, which are images that are not tagged and are not referenced by any container. You can run the following command:docker image prune
Remove All Unused Images: If you want to remove all images that are not associated with any container (both dangling and unused images), you can use the
-a
flag:docker image prune -a
This command will delete all images that do not have at least one container associated with them [2][3].
Force Removal: If you want to bypass the confirmation prompt, you can add the
-f
or--force
flag:docker image prune -a -f
Prune Multiple Object Types: Alternatively, you can use the
docker system prune
command, which removes not only unused images but also stopped containers and unused networks. To remove everything, including unused images, you can run:docker system prune
To include volumes in the cleanup, use:
docker system prune --volumes
By using these commands, you can effectively manage and free up disk space by removing images that are not in use by any containers.
Learn more: 1. Docker – Removing Dangling and Unused Images - Baeldung 2. How to remove old and unused Docker images - Stack Overflow 3. Prune unused Docker objects | Docker Docs