Docker 全流程实践

安装Docker

使用 apt 存储库安装:https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository

验证安装是否成功:sudo docker run --rm hello-world

单容器实践

实践流程:从 Docker Hub 拉取 nginx 镜像,创建容器并修改 nginx 的 web 页面,随后提交此容器使其成为副本并打上标签,上传到自己的 Docker Hub 账号中。

1. 拉取镜像

1
2
3
docker search nginx  # 搜索镜像
docker pull nginx # 拉取镜像
docker images # 查看本地镜像, 也可使用 docker image ls 命令

2. 启动容器

1
2
docker run -d --name nginx-web -p 81:80 nginx:latest
docker ps # 查看正在运行的容器
  • run: 启动新容器
  • -d: 后台运行容器
  • --name: 为容器指定名称, 不指定的话docker会自动生成随机名称
  • -p: 将容器的指定端口(80)映射到宿主机的指定端口(81),不指定将无法使用容器中的网络资源

3. 进入容器并修改web页面

1
docker exec -it nginx-web bash
  • exec: 在一个已经启动的容器中执行一个新的命令
  • -it: 分配一个伪终端
  • nginx-web: 容器的名称,也可使用容器ID
  • bash: 在容器中执行的命令,相当于/bin/bash

进入容器后执行此命令安装nano编辑器: apt update && apt install nano,也可安装vim,不过存储占用高于nano。
使用nano手动编辑/usr/share/nginx/html/index.html文件的内容为任意字符串,用于呈现在网页中。

也可跳过安装编辑器,直接使用此命令替换文件内容:echo "Docker's nginx is running" > /usr/share/nginx/html/index.html
此时再执行exit命令退出容器回到宿主机,执行curl 127.0.0.1:81命令即可看到修改后的内容:

alt text

4. 提交容器副本并打上标签

1
2
docker commit -m "First commit" -a lololowe nginx-web lolololowe/nginx-hub:1.0.0
docker images # 查看新镜像

此命令会将nginx-web(也可使用容器ID)容器提交为新的镜像lolololowe/nginx-hub,并且指定标签为1.0.0,若不指定则默认使用latest。lolololowe是docker hub的用户名,必须加上,否则后面提交此镜像的时候会选择以官方用户提交,结果自然是提交失败。
如需修改标签,可以使用此命令:

1
docker tag lolololowe/nginx-hub:1.0.0 lolololowe/nginx-hub:1.0.1

5. 推送镜像

1
2
docker login -u lolololowe  # 登录dokcer hub
docker push lolololowe/nginx-hub:1.0.0

注意:如果docker hub账户开启了双因素认证2FA,那么在登陆时需输入个人访问令牌而不是用户密码,具体参看官方文档:
https://docs.docker.com/security/for-developers/access-tokens/

alt text

alt text

6. Dockerfile

前面拉取镜像以及修改web页面的步骤也可用一个Dockerfile文件做到:

1
2
3
4
5
6
7
8
9
10
11
# 基于官方的nginx镜像
FROM nginx:latest

# 构建镜像时运行的命令
RUN echo "Docker's nginx is running" > /usr/share/nginx/html/index.html

# 声明容器运行时提供服务的端口,不会进行端口映射
EXPOSE 80

# 运行容器时运行的命令
CMD ["nginx", "-g", "daemon off;"]

构建镜像:

1
docker build -t lolololowe/nginx-hub:1.0.1 .

后台启动容器并验证服务状态:

1
2
3
docker run -d --name mynginx -p 82:80 lolololowe/nginx-hub:1.0.1
docker exec mynginx cat /usr/share/nginx/html/index.html
curl 127.0.0.1:82

推送镜像:

1
2
docker login -u lolololowe
docker push lolololowe/nginx-hub:1.0.1

alt text

Docker Compose 实践

实践流程:通过配置docker-compose.yml模板文件将mysql和phpmyadmin两个镜像同时构建并后台运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
version: '3.1'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: root

phpmyadmin:
image: phpmyadmin
restart: always
depends_on:
- db
ports:
- 8080:80
environment:
- PMA_ARBITRARY=1
  1. version: '3.1':表示Docker Compose文件的版本。不同版本有略微不同的功能和语法。
  2. services::定义要运行的所有docker服务。在此例中,为 db 和 phpmyadmin。
  3. dbphpmyadmin:服务名称,可以按需自定义。
  4. restart: always:定义重启策略为始终重启。
  5. image: mysql:5.7image: phpmyadmin/phpmyadmin :指定Docker以哪个镜像为基础创建容器。
  6. environment: 设置环境变量。对于mysql镜像,设置了root用户的密码。对于phpmyadmin镜像,设置了允许连接任意mysql服务器。
  7. depends_on: 定义服务之间的启动先后顺序。在这个例子中,在db服务启动之前,phpmyadmin服务不会启动。
  8. ports:- 8080:80:将phpmyadmin服务的80端口映射到宿主机的8080端口。

使用下面这条命令运行docker-compose.yml文件:

1
2
docker compose up -d
dokcer ps # 可以看到新增的2个容器

使用docker inspect docker-db-1 | grep IPAddress命令查看mysql容器的IP地址,然后浏览器打开 127.0.0.1:8080 ,输入mysql的IP地址以及用户名和密码即可登录成功:

alt text

需要删除容器则需要继续在docker-compose文件所在目录下执行此命令:docker compose down

常用命令

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
35
36
37
38
# 将用户加入docker组,以实现免root执行docker命令
sudo usermod -aG 用户名 docker

# 查看服务端和客户端的版本信息
docker version

# 运行容器
docker run -d --name 容器名称 -p 宿主机端口:容器端口 --restart unless-stopped -v 宿主机路径:容器路径 [用户名/]<镜像名>:<标签>

# 进入容器
docker exec -it 容器名称/ID /bin/bash

# 实时查看所有容器(包括已停止)的运行占用
docker stats -a

# 停止所有容器
docker stop $(docker ps -aq)

# 指定Dockerfile文件来构建镜像
docker build -f /path/to/your/Dockerfile -t [用户名/]<镜像名>:<标签> .

# 指定docker-compose文件来构建并运行镜像
docker compose up -d -f /path/to/your/docker-compose.yml

# 停止并删除容器
docker compose down -f /path/to/your/docker-compose.yml

# 提交容器为新镜像
docker commit -m "信息" -a "作者" 容器名称/ID [用户名/]<镜像名>:<标签>

# 推送镜像
docker push <用户名>/<镜像名>:<标签>

# 打包镜像
docker save -o 镜像.tar [用户名/]<镜像名>:<标签>

# 导入镜像
docker load -i 镜像.tar

注意事项

  1. Docker映射出来的端口无法被UFW管理,容易造成安全问题,解决方法请参看此项目:https://github.com/chaifeng/ufw-docker?tab=readme-ov-file#问题。或者映射端口时显式的指定宿主机监听的地址为本地环回地址,然后用Nginx反代映射的端口。

  2. 数据卷(Volume)和绑定挂载(Bind Mount)卷都可以实现数据共享以及数据持久化,数据卷的指定形如:-v volume_name:/path_in_container, 绑定挂载卷的指定形如:-v /path_in_host:/path_in_container, 使用docker volume ls命令可以查看所有的卷。

  3. exec选项只能用来在已经运行的容器中执行额外的命令,比如docker exec -it container_id /bin/bash可以在一个已经运行的容器中开一个新的bash shel到当前终端。而在启动容器的时候,则是直接将shell命令写在最后:docker run -it image:tag /bin/bash

  4. 重启策略为always时,如果容器异常终止或者docker守护进程重启,则会跟随重启。手动停止容器则不会重启。更多重启策略请参看官方文档:https://docs.docker.com/config/containers/start-containers-automatically/#use-a-restart-policy

参考文章

EXPOSE 声明端口, yeasy

Create and manage access tokens, Docker

ufw-docker, chaifeng

Use a restart policy, Docker