Bootstrap

【docker 总结】第五篇 - 制作镜像、数据盘

一,制作个性化镜像

根据公司的技术栈和技术选型,项目有个性化偏好,需要定制镜像,如:环境配置、软件版本等;

制作个性化镜像,无需每次都进行重复的配置环境,实现开箱即用;

制作个性化镜像有两种方式:

  • 基于 commit 制作

  • 根据 Dockerfile 构建

1,第一种:基于 commit 制作镜像

根据镜像启动容器,在容器内完成环境安装后,基于新的容器提交成为新的镜像,后续基于新镜像启动容器即可;

1,根据 ubuntu 镜像启动容器,添加新的文件,退出

// 启动容器并进入容器内部
BravedeMacBook-Pro:~ brave$ docker run -it ubuntu /bin/bash
// 创建文件
root@9ae402815828:/# cd /root
root@9ae402815828:~# touch my.txt
// 退出容器
root@9ae402815828:~# exit
exit

2,将新的容器提交成为新的镜像

// 将指定容器提交为镜像
BravedeMacBook-Pro:~ brave$ docker container commit -m"my ubuntu" -a"brave" 9ae402815828 brave/myubuntu:v1
sha256:23ed9c6a0c37e3648f995dd96c319e37d56631e6be1c7c0c37c97485be54baf5

// 查看本地镜像列表
BravedeMacBook-Pro:~ brave$ docker image ls
REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
brave/myubuntu   v1        23ed9c6a0c37   34 seconds ago   72.8MB
myroot           latest    45a3985181e6   17 hours ago     72.8MB
nginx            latest    f652ca386ed1   46 hours ago     141MB
ubuntu           latest    ba6acccedd29   7 weeks ago      72.8MB
brave/centos     v1        feb5d9fea6a5   2 months ago     13.3kB
hello-world      latest    feb5d9fea6a5   2 months ago     13.3kB
centos           6         5bf9684f4720   2 months ago     194MB
centos           latest    5d0da3dc9764   2 months ago     231MB

// 根据新镜像,启动容器
BravedeMacBook-Pro:~ brave$ docker run -it 23ed9c6a0c37 /bin/bash
root@625496544fa9:/# cd /root
root@625496544fa9:~# ls
my.txt

// 结论,基于新镜像启动的容器中,包含了新容器中的自定义内容

基于 commit 制作镜像,优点是直观,但不好管理;

2,第二种:根据 Dockerfile 构建

通过一个文件描述改变和操作,描述一个镜像的构建过程

  • Docker 的镜像是用一层一层的文件组成的

  • docker inspect命令可以查看镜像或者容器

  • Layers就是镜像的层文件,只读不能修改。基于镜像创建的容器会共享这些文件层

docker inspect centos

比如,制作一个 express 的镜像文件

// todo 添加详细实例

3,提交、发布镜像

  • docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

// 注册并登录 docker
docker login
// tag
docker image tag [imageName] [username]/[repository]:[tag]
// build
docker image build -t [username]/[repository]:[tag] .

// tag
docker tag express-demo zhangrenyang/express-demo:v1
// 推送
docker push zhangrenyang/express-demo:v1

数据盘

介绍

根据镜像创建一个容器,相当于在底层镜像上添加了一个读写层(就是容器),这样就可以改东西了;

如果将容器 rm 删掉了,就意味着整个都没了,即:整个镜像和容器层都没了;

那样的话,容器中存储的内容也就都丢掉了;

实际开发总,服务的日志需要保留;

mysql 容器删除后,数据不能丢失;

那么,可以将日志放到宿主机上;

这里需要使用 docker 的数据盘:

为容器创建数据盘:

三种方式:

  • bind mount 挂载点

  • volume 数据卷

  • tmpfs mount

备注:tmpfs mount 是挂载到内存中,很少用到;

volumes 数据卷

  • volumes 是 Docker管理宿主机文件系统的一部分(地址在 /var/lib/docker/volumes);

  • 如果没有指定卷,则会自动创建;

  • 建议使用--mount,更通用;

准备工作:删除所有容器

// 停掉所有容器 stop 比较优雅相对慢一些,kill 比较快
BravedeMacBook-Pro:~ brave$ docker container stop $(docker container ps -a -q)
625496544fa9
9ae402815828
9c68a087624c
4e7e482c7938
d0f4ff488427
86dfeaa9638c
f08109d1269d
7f87bc954787

// 删除所有容器
BravedeMacBook-Pro:~ brave$ docker container rm $(docker container ps -a -q)
625496544fa9
9ae402815828
9c68a087624c
4e7e482c7938
d0f4ff488427
86dfeaa9638c
f08109d1269d
7f87bc954787

// 查看所有容器
BravedeMacBook-Pro:~ brave$ docker container ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

创建数据卷

查看 volume 命令

BravedeMacBook-Pro:~ brave$ docker volume --help

Usage:  docker volume COMMAND

Manage volumes

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove all unused local volumes
  rm          Remove one or more volumes

Run 'docker volume COMMAND --help' for more information on a command.

创建数据卷

创建数据卷存放 nginx 日志

BravedeMacBook-Pro:~ brave$ docker volume create nginx-logger
nginx-logger

在宿主机硬盘上的哪个位置?

/var/lib/docker/volumes/nginx-logger/_data

// 查看数据卷列表
BravedeMacBook-Pro:~ brave$ docker volume ls
DRIVER    VOLUME NAME
local     nginx-logger

// 查看指定数据卷的详情
BravedeMacBook-Pro:~ brave$ docker volume inspect nginx-logger
[
    {
        "CreatedAt": "2021-12-04T12:38:33Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/nginx-logger/_data",
        "Name": "nginx-logger",
        "Options": {},
        "Scope": "local"
    }
]

如何使用数据卷?

挂载数据卷

再创建一个数据卷

BravedeMacBook-Pro:~ brave$ docker volume create nginx-html
nginx-html

将容器中的某个位置挂载到数据卷

根据 nginx 镜像创建一个后台运行的 nginx 容器,命名为 nginx1

将 nginx 的根目录(/usr/share/nginx/html)挂载到数据卷 nginx-html(宿主机的 /var/lib/docker/volumes/nginx-logger/_data)

BravedeMacBook-Pro:~ brave$ docker run -d --name nginx1 --mount src=nginx-html,dst=/usr/share/nginx/html nginx
0f4d6a172bc863765f3c0b32605339d87992aea1d9b91ed34eb003a3ed889dca

nginx-html 数据卷
/usr/share/nginx/html 是 nginx 的根目录

将 nginx 的根目录挂载到了数据卷 nginx-html 上,即 nginx 的根目录指向宿主机的nginx-html目录:"/var/lib/docker/volumes/nginx-logger/_data"

启动后,查看数据卷内的数据

解决 MAC OS 问题

BravedeMacBook-Pro:~ brave$ docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
5e0b432e8ba9: Pull complete 
Digest: sha256:45ee40a844048c2f6d0105899c1a17733530b56d481612608aab5e2e4048570b
Status: Downloaded newer image for debian:latest
/ # ls
bin          dev          home         media        proc         sbin         tmp
boot         etc          init         mnt          root         srv          usr
containers   grpcfuse.ko  lib          opt          run          sys          var

// 进入 docker 目录
/ # cd /var/lib/docker/
/var/lib/docker # ls
buildkit    containers  image       network     overlay2    plugins     runtimes    swarm       tmp         trust       volumes

// 查看 docker 卷
/var/lib/docker # cd volumes/
/var/lib/docker/volumes # ls
backingFsBlockDev  metadata.db        nginx-html         nginx-logger

// 进入 nginx-html/_data/
/var/lib/docker/volumes # cd nginx-html/_data/
/var/lib/docker/volumes/nginx-html/_data # ls
50x.html    index.html

还可以再进入到容器中的 nginx 根目录(此时容器内 nginx 的根目录与宿主机 nginx-html 数据卷已同步)

BravedeMacBook-Pro:~ brave$ docker container exec -it 0f4d6a172bc863 /bin/bash
root@0f4d6a172bc8:/# cd /usr/share/nginx/html
root@0f4d6a172bc8:/usr/share/nginx/html# ls
50x.html  index.html

在容器内创建一个文件(看数据卷会不会同步)

root@0f4d6a172bc8:/usr/share/nginx/html# touch test.html

宿主机看一下,文件已经同步:

/var/lib/docker/volumes/nginx-html/_data # ls
50x.html    index.html  test.html

在宿主机创建一个文件

/var/lib/docker/volumes/nginx-html/_data # touch test1.html

在容器内查看,已同步:

root@0f4d6a172bc8:/usr/share/nginx/html# ls
50x.html  index.html  test.html  test1.html

挂载有两种方法,上边讲的是第一种,很啰嗦

docker run -d --name nginx1 --mount src=nginx-html,dst=/usr/share/nginx/html nginx

第二种,路径的映射可以简写

做 volume 映射 数据卷名称:容器目录

BravedeMacBook-Pro:~ brave$ docker run -d --name nginx2 -v nginx-html:/usr/share/nginx/html nginx
2bb332f19311592bea94715f3494bbfc2ddb2e4c1c1ca017d8b4c6d43241dc83

没有映射端口,都是 80,会不会冲突?

相当于两台机器,相互独立,与外部的宿主机没有关系;

进去目录看看,内容是一样的:

BravedeMacBook-Pro:~ brave$ docker container exec -it 2bb332f19311 /bin/bash
root@2bb332f19311:/# cd /usr/share/nginx/html
root@2bb332f19311:/usr/share/nginx/html# ls
50x.html  index.html  test.html  test1.html

删除数据卷

BravedeMacBook-Pro:~ brave$ docker volume rm nginx-html
Error response from daemon: remove nginx-html: volume is in use - [0f4d6a172bc863765f3c0b32605339d87992aea1d9b91ed34eb003a3ed889dca, 2bb332f19311592bea94715f3494bbfc2ddb2e4c1c1ca017d8b4c6d43241dc83]

有两个容器正在使用,不能删除,想要删除需要先把这两个容器停掉

BravedeMacBook-Pro:~ brave$ docker container ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED        STATUS        PORTS     NAMES
2bb332f19311   nginx     "/docker-entrypoint.…"   24 hours ago   Up 24 hours   80/tcp    nginx2
0f4d6a172bc8   nginx     "/docker-entrypoint.…"   25 hours ago   Up 25 hours   80/tcp    nginx1

BravedeMacBook-Pro:~ brave$ docker container kill 2bb332f19311 0f4d6a172bc8
2bb332f19311
0f4d6a172bc8

两个容器已经停掉了,再删除发现还是不行

BravedeMacBook-Pro:~ brave$ docker volume rm nginx-html
Error response from daemon: remove nginx-html: volume is in use - [0f4d6a172bc863765f3c0b32605339d87992aea1d9b91ed34eb003a3ed889dca, 2bb332f19311592bea94715f3494bbfc2ddb2e4c1c1ca017d8b4c6d43241dc83]

这是因为,两个容器挂载了数据卷

可以把容器删掉

// 查看数据卷列表
BravedeMacBook-Pro:~ brave$ docker volume ls
DRIVER    VOLUME NAME
local     nginx-html
local     nginx-logger

// -f dangling=true 过滤悬挂的,即查看没有任何容器引用的数据卷
BravedeMacBook-Pro:~ brave$ docker volume ls -f dangling=true
DRIVER    VOLUME NAME
local     nginx-logger

这种是可以直接通过 docker volume rm 删掉的
docker volume rm nginx-logger
也可以一次将所有没有引用的数据卷都删掉
docker volume prune

bind mount 数据卷

如果 var/lib/docker/volumes空间太小不够,就要放到其他地方,此时就不能用volume了

需要使用绑定挂载

docker run -v /mnt:/mnt -it --name logs centos bash
将宿主机的/mnt 目录映射为这个容器的 /mnt 目录

注意个 volume -v 的区别:

docker run -d --name nginx2 -v nginx-html:/usr/share/nginx/html nginx

这个-v nginx-html:/usr/share/nginx/html
冒号左侧是数据卷名

BravedeMacBook-Pro:~ brave$ docker run -v /mnt:/mnt -it --name logs centos bash
docker: Error response from daemon: Mounts denied: 
The path /mnt is not shared from the host and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> Resources -> File Sharing.
See https://docs.docker.com/desktop/mac for more info.

创建容器后,在容器的/mnt 目录创建一个 txt 文件,

宿主机的/mnt 会同步出现 txt 文件

这样就不会收到 docker/volumes 的限制,想吧数据放在哪就可以挂载到哪里

可以两个容器用一个数据盘 比如负载情况,日志可以写到一起去

创建容器

BravedeMacBook-Pro:~ brave$ docker create -v /Users/brave/logger:/logger --name logger centos
c86fb1eb39ba1b87b84af741818b51d6e65e705934382fd3cc206e2d79f82fc1

BravedeMacBook-Pro:~ brave$ docker container ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                     PORTS     NAMES
06531bf11e91   centos    "/bin/bash"              43 seconds ago   Created                              logger

docker create和 docker run 的区别是创建容器但不启动

我们创建它的作用不是用来启动的,而是数据挂载策略:用宿主机的/logger,挂载容器中的 /logger

继承容器:

--volumes-from:从哪个容器继承数据卷(logger挂载了数据卷)

// logger_test1 继承 logger 容器的数据卷
BravedeMacBook-Pro:~ brave$ docker run --volumes-from logger --name logger_test1 -it centos bash
[root@4ce4b9717b5c /]# 

在logger_test1容器内,即/logger 目录下创建一个文件

同理再创建一个logger_test2,/logger 目录下存在刚刚logger_test1创建的文件

logger_test2进入/logger 目录创建文件,logger_test1 也能看到

退出后,宿主机也能看到

优势,不需要知道数据卷的配置,只需要知道继承就好了