目录
- 1 什么是Docker?
- 2 Docker 和 DevOps[开发/运维]
- 3 Docker 架构
- 3.1 Docker 中术语说明
- 4 Docker安装
- 6 Docker命令
- 6.1 镜像命令
- 6.2 容器命令
- 6.3 常用其他命令
- 6.3.1查看日志
- 6.3.2docker top container
- 6.3.3 docker inspect docker
- 6.3.4 进入正在运行的容器
- 6.3.5 拷贝容器中的文件到宿主机
- 7 测试部署Tomcat 服务器
- 7.1 下载镜像运行容器
- 7.2 webapp 下添加index.html 进行测试
- 8 Docker可视化工具 Portainer
- 9 Docker 镜像详解
- 9.1 镜像与联合文件系统
- 9.2 镜像拉取过程解读
- 10 Commit 镜像
- 11 Volume 数据卷
- 11.1 容器数据卷挂载命令
- 11.2 匿名卷和具名卷
- 12 数据卷容器
- 12.1 创建一个数据卷容器
- 12.2 创建新容器使用这个数据卷容器
- 12.3 使用数据卷容器的优势
- 13 DockerFile
- 13.1 DockerFile脚本命令
- 13.2 Net6项目通过Docker发布DockerFile如何编写
- 14 Docker全流程小结
1 什么是Docker?
Docker 是一种用于构建、部署和运行应用程序的开源平台,它使用容器技术来实现轻量级、可移植和自包含的应用程序环境。Docker 的核心思想是将应用程序及其依赖项打包到一个称为容器的封闭单元中,从而消除了在不同环境中运行应用程序时可能出现的许多兼容性和依赖性问题。
相较于虚拟机技术而言
- 传统虚拟机需要需要虚拟出一套完整的硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
- Docker使用容器化技术, 每个容器是相互隔离的,且每个容器都有一个属于自己的文件系统,互不影响.容器包含应用及其所有依赖项,可以在不同的系统上直接运行.
- 由于Docker容器共享宿主机的内核,无需额外的操作系统,占用资源较少。
2 Docker 和 DevOps[开发/运维]
1应用更快速的交付和部署
Docker 打包成镜像发布测试,一键运行 .
2更编辑的升级和扩缩容
使用Docker后,部署应用就像搭积木一样,项目打包成惊吓过后,可以水平直接扩容到其他的服务器上
3更简单的系统运维
在容器化之后,我们的开发和测试环境是高度一致的
4更高效的计算资源利用
Docker 是内核级别的虚拟化技术,可以在一个物理机上运行很多的容器实例,服务器的性能可以被压榨到极致
3 Docker 架构
3.1 Docker 中术语说明
-
镜像[Image]: 镜像是Docker中的关键概念,它是一个轻量级、独立的可执行软件包,包含运行应用程序所需的一切,包括代码、运行时、库、环境变量和配置文件。镜像是容器的基础,通过镜像可以创建并运行一个或多个容器实例。
-
容器[Container]: 通过镜像可以实例化多个容器实例 ,这意味着容器中也包含了应用程序所需的一切.对容器的操作包括 删除 运行 启动
镜像和容器的关系 相当于Java程式中.Class 和 实例对象. 一个.Class可以new出不同的实例对象. 镜像是模版,依靠模版可以创建不同的容器
-
仓库[Repository]: 仓库用于集中存储和管理 Docker 镜像,使得开发者和团队可以方便地访问和共享这些镜像。常用的镜像仓库为DockerHub 阿里云镜像库等.
-
客户端:
-
服务端:
4 Docker安装
环境说明
Centos8 [使用dnf指令来替代yum 下载依赖包]
安装步骤
- 卸载旧版本
sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine
- 配置Docker的国内仓库地址
sudo dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.reposudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo [官方文档默认是使用国外的镜像,不建议使用这个,下载慢]
- 安装docker相关的Package
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
- 启动docker
sudo systemctl start docker
docker version
- 设置Docker镜像仓库 /etc/docker/daemon.json
registry-mirrors
是一个数组,它可以包含多个镜像加速地址。添加镜像加速地址可以让 Docker 优先从这些地址拉取镜像,而不是直接从 Docker Hub 拉取,从而提高拉取速度,特别是在国内网络环境下,可以有效避免网络连接问题和拉取速度慢的问题
{ "registry-mirrors":[ "https://docker.1ms.run", "https://doublezonline.cloud", "https://dislabaiot.xyz", "https://docker.fxxk.dedyn.io", "https://dockerpull.org", "https://docker.unsee.tech", "https://hub.rat.dev", "https://docker.1panel.live", "https://docker.nastool.de", "https://docker.zhai.cm", "https://docker.5z5f.com", "https://a.ussh.net", "https://docker.udayun.com", "https://hub.geekery.cn" ] }
- 测试运行docker
sudo docker run hello-world
-
查看镜像
docker images
6 Docker命令
docker命令操作手册
6.1 镜像命令
- docker images 查询本地镜像 等价于 docker image ls
[root@hcss-ecs-b45b ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 20 months ago 13.3kB# 说明
REPOSITORY[镜像名] TAG[标签] IMAGE ID[镜像ID] CREATED[创建时间] SIZE[大小]# 可选项
-a 获得所有的镜像
-q 只获得镜像的ID
- docker image pull name[:tag] 下载镜像
[root@hcss-ecs-b45b ~]# docker pull mysql
Using default tag: latest # 当默认不写镜像的版本时,将会使用latest
latest: Pulling from library/mysql
2c0a233485c3: Pull complete # 分层下载,这个是docker image的核心 ,与联合文件系统挂钩
cb5a6a8519b2: Pull complete
570d30cf82c5: Pull complete
a841bff36f3c: Pull complete
80ba30c57782: Pull complete
5e49e1f26961: Pull complete
ced670fc7f1c: Pull complete
0b9dc7ad7f03: Pull complete
cd0d5df9937b: Pull complete
1f87d67b89c6: Pull complete
Digest: sha256:0255b469f0135a0236d672d60e3154ae2f4538b146744966d96440318cc822c6 #签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址 等价于 docker pull docker.io/library/mysql:latest
- docker image remove / docker rmi 删除镜像
# docker image remove 镜像ID 根据ID去删除镜像
docker image remove d2c94e258dcb -f# docker image -aq 获得所有的镜像ID
docker image remove $(docker image -aq ) -f # 可选项
-f 强制删除
6.2 容器命令
所有的容器操作都需要依赖于镜像的存在
- docker container run /docker run 新建一个容器并启动 docker run | Docker Docs
[root@hcss-ecs-b45b ~]# docker run -it --name centos_1 centos /bin/bash
[root@072e975e99e8 /]#
# 可选项
--name 給容器取別名
-p 设置运行端口
-it 内部交互运行
-d 后台运行 [ps:后台运行的容器存在一个坑,当容器中没有一个持续运行的服务/进程时,容器启动后将会很快退出]
- docker ps 查询当前正在运行的容器
[root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ebd1e2a942ec centos "/bin/bash" 2 minutes ago Up 2 minutes centos_1
[root@hcss-ecs-b45b ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a88275c5bae6 centos "/bin/bash" About a minute ago Exited (0) About a minute ago cranky_rubin
5f4ecc20b3bc centos "-i bin/bash" 2 minutes ago Created xenodochial_keller
0d011149522d centos "-it bin/bash" 3 minutes ago Created affectionate_kowalevski
9ac64e0ecfd0 d2c94e258dcb "/hello" 9 days ago Exited (0) 9 days ago elegant_grothendieck# 可选项
-a 查询所有的容器记录[包括已关闭的]
- 退出容器
exit 退出并关闭容器
ctrl+q+p 退出但不关闭容器
- 删除容器
docker rm 容器Id #根据容器ID制定删除容器
docker rm -f $(docker ps -aq) # 根据所有的容器ID删除所有存在的容器
- 启动和关闭容器
# docker stop 容器ID/name 停止容器
[root@hcss-ecs-b45b ~]# docker stop ebd1e2a942ec
ebd1e2a942ec
[root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES# docker start 容器ID/name 开启容器
[root@hcss-ecs-b45b ~]# docker start ebd1e2a942ec
ebd1e2a942ec
[root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ebd1e2a942ec centos "/bin/bash" 12 minutes ago Up 4 seconds centos_1# docker restart 容器ID/name 重启容器
# docker kill 容器ID/name 强制停止容器
docker stop和 docker kill 关闭容器的区别:
docker stop
命令会先向容器发送一个SIGTERM
信号,给容器内的进程一些时间来进行优雅的关闭操作(比如保存数据、关闭文件句柄等),如果一段时间后(默认等待 10 秒)容器内的进程还没有停止,就会再发送一个SIGKILL
信号强制终止容器内的进程,从而停止容器.
docker kill
命令会向容器发送一个SIGKILL
信号,直接强制终止容器内的所有进程,使得容器迅速停止运行。不过这种方式不建议在容器内有重要数据需要保存等情况时随意使用,因为可能会导致数据丢失或未保存完整等问题,更适合在容器出现无响应等异常情况且无法通过正常方式停止时采用.
6.3 常用其他命令
6.3.1查看日志
docker container logs/docker logs [docker logs [OPTIONS] CONTAINER]
[root@hcss-ecs-b45b ~]# docker logs centos_1
[root@ebd1e2a942ec /]#
[root@ebd1e2a942ec /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@ebd1e2a942ec /]# exit
6.3.2docker top container
查看容器中运行的进程信息
[root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ebd1e2a942ec centos "/bin/bash" 56 minutes ago Up 43 minutes centos_1
[root@hcss-ecs-b45b ~]# docker top ebd1e2a942ec
UID PID PPID C STIME TTY TIME CMD
root 425797 425774 0 10:16 pts/0 00:00:00 /bin/bash
6.3.3 docker inspect docker
查看容器配置详情
[root@hcss-ecs-b45b ~]# docker inspect ebd1e2a942ec
[{"Id": "ebd1e2a942ec644fdef45aec83e2d739040040d9e79638e4cdc714296a7c73ea","Created": "2025-01-06T02:04:15.108588718Z","Path": "/bin/bash","Args": [],"State": {"Status": "running","Running": true,"Paused": false,"Restarting": false,"OOMKilled": false,"Dead": false,"Pid": 425797,"ExitCode": 0,"Error": "","StartedAt": "2025-01-06T02:16:53.639121254Z","FinishedAt": "2025-01-06T02:15:44.874986996Z"},"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6","ResolvConfPath": "/var/lib/docker/containers/ebd1e2a942ec644fdef45aec83e2d739040040d9e79638e4cdc714296a7c73ea/resolv.conf","HostnamePath": "/var/lib/docker/containers/ebd1e2a942ec644fdef45aec83e2d739040040d9e79638e4cdc714296a7c73ea/hostname","HostsPath": "/var/lib/docker/containers/ebd1e2a942ec644fdef45aec83e2d739040040d9e79638e4cdc714296a7c73ea/hosts","LogPath": "/var/lib/docker/containers/ebd1e2a942ec644fdef45aec83e2d739040040d9e79638e4cdc714296a7c73ea/ebd1e2a942ec644fdef45aec83e2d739040040d9e79638e4cdc714296a7c73ea-json.log","Name": "/centos_1","RestartCount": 0,"Driver": "overlay2","Platform": "linux","MountLabel": "","ProcessLabel": "","AppArmorProfile": "","ExecIDs": null,"HostConfig": {"Binds": null,"ContainerIDFile": "","LogConfig": {"Type": "json-file","Config": {}},"NetworkMode": "bridge","PortBindings": {},"RestartPolicy": {"Name": "no","MaximumRetryCount": 0},"AutoRemove": false,"VolumeDriver": "","VolumesFrom": null,"ConsoleSize": [43,187],"CapAdd": null,"CapDrop": null,"CgroupnsMode": "host","Dns": [],"DnsOptions": [],"DnsSearch": [],"ExtraHosts": null,"GroupAdd": null,"IpcMode": "private","Cgroup": "","Links": null,"OomScoreAdj": 0,"PidMode": "","Privileged": false,"PublishAllPorts": false,"ReadonlyRootfs": false,"SecurityOpt": null,"UTSMode": "","UsernsMode": "","ShmSize": 67108864,"Runtime": "runc","Isolation": "","CpuShares": 0,"Memory": 0,"NanoCpus": 0,"CgroupParent": "","BlkioWeight": 0,"BlkioWeightDevice": [],"BlkioDeviceReadBps": [],"BlkioDeviceWriteBps": [],"BlkioDeviceReadIOps": [],"BlkioDeviceWriteIOps": [],"CpuPeriod": 0,"CpuQuota": 0,"CpuRealtimePeriod": 0,"CpuRealtimeRuntime": 0,"CpusetCpus": "","CpusetMems": "","Devices": [],"DeviceCgroupRules": null,"DeviceRequests": null,"MemoryReservation": 0,"MemorySwap": 0,"MemorySwappiness": null,"OomKillDisable": false,"PidsLimit": null,"Ulimits": [],"CpuCount": 0,"CpuPercent": 0,"IOMaximumIOps": 0,"IOMaximumBandwidth": 0,"MaskedPaths": ["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/proc/scsi","/sys/firmware","/sys/devices/virtual/powercap"],"ReadonlyPaths": ["/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]},"GraphDriver": {"Data": {"LowerDir": "/var/lib/docker/overlay2/fac3898fd6c40158d9c2e476440bf753f79f155fd2d4e075f2c7214e8c950285-init/diff:/var/lib/docker/overlay2/2ae57a6edb0cd10b4dfc7f6b2ff63155f8e88610fddb64316f0103542548b6cc/diff","MergedDir": "/var/lib/docker/overlay2/fac3898fd6c40158d9c2e476440bf753f79f155fd2d4e075f2c7214e8c950285/merged","UpperDir": "/var/lib/docker/overlay2/fac3898fd6c40158d9c2e476440bf753f79f155fd2d4e075f2c7214e8c950285/diff","WorkDir": "/var/lib/docker/overlay2/fac3898fd6c40158d9c2e476440bf753f79f155fd2d4e075f2c7214e8c950285/work"},"Name": "overlay2"},"Mounts": [],"Config": {"Hostname": "ebd1e2a942ec","Domainname": "","User": "","AttachStdin": true,"AttachStdout": true,"AttachStderr": true,"Tty": true,"OpenStdin": true,"StdinOnce": true,"Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd": ["/bin/bash"],"Image": "centos","Volumes": null,"WorkingDir": "","Entrypoint": null,"OnBuild": null,"Labels": {"org.label-schema.build-date": "20210915","org.label-schema.license": "GPLv2","org.label-schema.name": "CentOS Base Image","org.label-schema.schema-version": "1.0","org.label-schema.vendor": "CentOS"}},"NetworkSettings": {"Bridge": "","SandboxID": "bedce9df3d4b747ac57db3bd02dfa39405ffbea863c1f532546a21d4737db491","SandboxKey": "/var/run/docker/netns/bedce9df3d4b","Ports": {},"HairpinMode": false,"LinkLocalIPv6Address": "","LinkLocalIPv6PrefixLen": 0,"SecondaryIPAddresses": null,"SecondaryIPv6Addresses": null,"EndpointID": "5a65b7f6fbe0b7b334692fb8be91d159d91b82e0f1018d21636cfdfdaac0ad02","Gateway": "172.17.0.1","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"IPAddress": "172.17.0.2","IPPrefixLen": 16,"IPv6Gateway": "","MacAddress": "02:42:ac:11:00:02","Networks": {"bridge": {"IPAMConfig": null,"Links": null,"Aliases": null,"MacAddress": "02:42:ac:11:00:02","NetworkID": "953e61feef74cf93fb50eba4d779e8ff328710f29558ba628ac3a5a2f8e10195","EndpointID": "5a65b7f6fbe0b7b334692fb8be91d159d91b82e0f1018d21636cfdfdaac0ad02","Gateway": "172.17.0.1","IPAddress": "172.17.0.2","IPPrefixLen": 16,"IPv6Gateway": "","GlobalIPv6Address": "","GlobalIPv6PrefixLen": 0,"DriverOpts": null,"DNSNames": null}}}}
]
6.3.4 进入正在运行的容器
docker attach 容器ID/ docker exit 容器ID
docker attach ca9775ef831e
docker exec -it ca9775ef831e /bin/bash
通过容器的名称或者容器 ID 来使用这个命令可以进入容器,但它与
docker exec
有所不同。使用docker attach
进入容器后,会连接到容器内正在运行的主进程的标准输入、输出和错误输出流,这意味着如果容器内的主进程结束了,你也会随之退出容器;并且如果同时有多个终端使用docker attach
连接到同一个容器,输入的内容会在所有连接的终端上显示,可能会相互干扰,所以在实际使用中相对docker exec
有一定局限性。
6.3.5 拷贝容器中的文件到宿主机
[root@hcss-ecs-b45b ~]# docker cp centos_1:text.txt testDic
Successfully copied 1.54kB to /root/testDic# 拷贝是一个手动过程,未来可以使用-v卷的技术来实现自动数据同步
# docker cp是 Docker 命令之一,主要用于在容器和本地文件系统之间复制文件或目录。这是一个非常实用的命令,方便用户在主机和容器之间传递数据
7 测试部署Tomcat 服务器
7.1 下载镜像运行容器
# 下载tomcat 镜像
docker pull image tomcat# 根据镜像运行成为服务容器 端口分配到8080端口上 内部容器的端口同样为8080端口
docker run --name my_tomcat -it -p 8080:8080 tomcat
关于端口分配问题 如下图所示 ,为了能通过公网访问到docker上运行的容器服务,需要开通防火墙 安全组等配置
linux 防火墙开放8080端口
# 检查防火墙是否运行 systemctl status firewalld ## 如果是dead状态 开启防火墙 system start firewalld ## 添加防火墙策略 firewall-cmd --permanent --add-port=8080/tcp## 重启防火墙服务 让新规则生效 firewall-cmd --reload
华为云主机开放8080 安全组
7.2 webapp 下添加index.html 进行测试
### 进入运行的tomcat 服务
[root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2ea15cfdf86b tomcat "catalina.sh run" 54 minutes ago Up 54 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp my_tomcat
[root@hcss-ecs-b45b ~]# docker exec -it my_tomcat /bin/bash
root@2ea15cfdf86b:/usr/local/tomcat# ## 创建hello 文件夹
mkdir hello
## 创建 index.html
touch index.html
## 编辑index.html 内容
vim index.html
> vim 编辑index.html 时提示没有vim 命令 需要下载它
> apt-get update
# apt-get:是一个功能强大的软件包管理工具,用于在 Debian、Ubuntu 和其他基于 Debian 的系统中管理软件包。它可以安装、升级、移除软件包,以及更新软件包列表等。update:是 apt-get 的一个子命令,它的主要功能是从软件源(也叫软件仓库)中获取最新的软件包信息,包括可用软件包的列表、版本更新、依赖关系等信息,但不会对已安装的软件包进行实际的升级操作。
apt-update
# 下载vim
apt-get install vim ## 重新编辑index.html
输入Hello I am Tomcat Welcom to the Deployed Program!
8 Docker可视化工具 Portainer
Docker Portainer 是一个用于管理 Docker 环境的开源工具,它提供了一个直观的 Web 界面,让你可以更方便地管理 Docker 容器、镜像、网络、卷等资源。
# 创建具名卷
docker volume create portainer_datas# 运行Portainer
docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_datas:/data portainer/portainer
- 这个命令的解释如下:
-d
:以守护进程模式运行容器,在后台运行。-p 8080:9000
:将主机的 8080端口映射到容器的 9000 端口,以便通过主机的 9000 端口访问 Portainer 服务。--name portainer
:为容器指定名称为portainer
。--restart always
:如果容器停止或系统重启,会自动重启容器。-v /var/run/docker.sock:/var/run/docker.sock
:将 Docker 的 Unix 套接字文件挂载到容器中,这样 Portainer 可以与 Docker 守护进程通信。-v portainer_data:/data
:将之前创建的portainer_data
数据卷挂载到容器的/data
目录,用于存储 Portainer 的数据。portainer/portainer
:这是 Portainer 的 Docker 镜像名称。
访问 Portainer 服务
打开浏览器,输入 http://<your_centos_ip>:9000,其中 <your_centos_ip> 是你的 CentOS 服务器的 IP 地址。
设置密码后重启 portainer 容器服务
[root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9f2eea8e97d1 portainer/portainer "/portainer" 9 minutes ago Up 9 minutes 8000/tcp, 9443/tcp, 0.0.0.0:8080->9000/tcp, :::8080->9000/tcp portainer[root@hcss-ecs-b45b ~]# docker restart 9f2eea8e97d1
9f2eea8e97d1
登录portainer 后界面
9 Docker 镜像详解
Docker镜像是Docker容器的构建块,是一种轻量级、独立的可执行软件包。它包含了运行应用程序所需的所有代码、运行时、库、环境变量和依赖项。镜像可以看作是一个只读的模板,用于创建容器实例。
Docker 镜像采用分层结构。每个镜像由一个或多个只读层组成。例如,一个简单的基于 Ubuntu 的镜像可能有多个分层,包括基础操作系统层(如 Ubuntu 的文件系统基础层)、安装软件包层(如安装了 Python 包后的层)等。这种分层结构的好处是可以复用。当多个镜像基于相同的基础镜像构建时,它们可以共享基础层。节省内存空间和网络开销
9.1 镜像与联合文件系统
联合文件系统(Union File System,UFS)是实现 Docker 镜像分层存储和高效利用存储资源的关键技术。Docker 镜像的分层结构是建立在联合文件系统之上的,通过联合文件系统可以将多个只读层(这些层构成了镜像)组合在一起,形成一个统一的文件系统视图。
Docker镜像的每一层都是一个文件系统 ,联合文件系统能够将多个文件系统挂载到一个统一的挂载点。
9.2 镜像拉取过程解读
-
连接镜像仓库
客户端会尝试连接到配置的镜像仓库。如果没有特别指定,Docker 会默认连接到 Docker Hub(
https://hub.docker.com/
)。它会使用仓库的 API 端点来获取关于redis
镜像的信息。 -
获取镜像清单文件(manifest)
连接成功后,客户端会从镜像仓库获取
redis
镜像的清单文件。这个文件包含了镜像的详细信息,如镜像的分层结构、每层的哈希值、镜像支持的架构.清单文件就像是镜像的一个 “索引”,帮助客户端了解需要拉取哪些内容来构建完整的镜像。 -
拉取镜像分层
根据清单文件中的信息,Docker 客户端会开始拉取镜像的各个分层。每个分层都是一个独立的文件系统部分,这些分层会被存储在本地的 Docker 存储目录(通常是
/var/lib/docker/
下的相关目录)中。在拉取过程中,会显示拉取的进度,包括已经拉取了多少分层、还剩下多少分层等信息。
10 Commit 镜像
docker commit
是一个用于从容器创建新的 Docker 镜像的命令。当你对一个正在运行的容器进行了一些修改(如安装软件、修改配置文件等),并且希望将这些修改保存为一个新的镜像以便后续复用或部署时,就可以使用这个命令
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]# OPTIONS(选项):
-a, --author:用于指定镜像作者的信息,格式为 “姓名 < 邮箱>”。例如,-a "John Doe <johndoe@example.com>"。
-c, --change:可以在提交镜像时应用 Dockerfile 指令。这允许你在创建镜像时进行一些诸如修改容器的启动命令、添加环境变量等操作。例如,-c 'CMD ["python", "app.py"]'会修改容器的启动命令为执行python app.py。
-m, --message:用于添加提交镜像的注释信息,描述这个镜像的修改内容或者用途等。例如,-m "Added new software and configured"。
-p, --pause:默认情况下,在提交镜像时容器会被暂停,以确保数据的一致性。如果不想暂停容器,可以使用--no - pause选项。不过,不暂停容器可能会导致提交的镜像数据不一致。
在运行的Tomcat容器基础上 commit 创建一个新的镜像
[root@hcss-ecs-b45b ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest f62f518e5c5c 4 weeks ago 467MB
nginx latest f876bfc1cc63 5 weeks ago 192MB
redis latest 2724e40d4303 3 months ago 117MB
portainer/portainer latest 5f11582196a4 2 years ago 287MB
centos latest 5d0da3dc9764 3 years ago 231MB
[root@hcss-ecs-b45b ~]# docker run -it --name my_tomcat_1 tomcat /bin/bash
root@0d55f2539bf2:/usr/local/tomcat# ls
bin BUILDING.txt conf CONTRIBUTING.md lib LICENSE logs native-jni-lib NOTICE README.md RELEASE-NOTES RUNNING.txt temp webapps webapps.dist work
root@0d55f2539bf2:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@0d55f2539bf2:/usr/local/tomcat# ls
bin BUILDING.txt conf CONTRIBUTING.md lib LICENSE logs native-jni-lib NOTICE README.md RELEASE-NOTES RUNNING.txt temp webapps webapps.dist work
root@0d55f2539bf2:/usr/local/tomcat# cd webapps
root@0d55f2539bf2:/usr/local/tomcat/webapps# ls
docs examples host-manager manager ROOT
root@0d55f2539bf2:/usr/local/tomcat/webapps# [root@hcss-ecs-b45b ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0d55f2539bf2 tomcat "/bin/bash" About a minute ago Up About a minute 8080/tcp my_tomcat_1
9f2eea8e97d1 portainer/portainer "/portainer" 4 hours ago Up 4 hours 8000/tcp, 9443/tcp, 0.0.0.0:8080->9000/tcp, :::8080->9000/tcp portainer
[root@hcss-ecs-b45b ~]# docker commit -a='lyf' -m='add default webapps' 0d55f2539bf2 my_tomcat:1.0
# 现在,就可以使用 my_tomcat:1.0 这个新镜像来创建新的容器,这里包含了所做的修改。
sha256:bf4e9cad830c78f927e4282e3edc7535954589db239b2b99f115cf428a427dec
[root@hcss-ecs-b45b ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my_tomcat 1.0 bf4e9cad830c 8 seconds ago 472MB
tomcat latest f62f518e5c5c 4 weeks ago 467MB
nginx latest f876bfc1cc63 5 weeks ago 192MB
redis latest 2724e40d4303 3 months ago 117MB
portainer/portainer latest 5f11582196a4 2 years ago 287MB
centos latest 5d0da3dc9764 3 years ago 231MB
11 Volume 数据卷
在容器化环境中,当容器被销毁时,容器内部的数据通常会丢失,因此需要一种方法来确保数据的持久性.
Docker卷是一种用于在Docker容器和主机之间共享数据的机制。它允许将主机文件系统中的目录或文件挂载到容器中,从而使容器能够访问主机上的数据,并且这些数据在容器销毁后仍然保持持久。Docker卷可以用于多种用途,包括数据持久性、数据共享、备份和恢复等。它们提供了一种简单而有效的方式来处理容器中的数据,使得数据管理更加灵活和可靠。通过使用Docker卷,容器化应用程序可以更方便地访问和管理数据,并且在容器之间进行迁移和扩展时能够保持数据的一致性和持久性。
总的来说,就是容器数据的持久化和同步操作! 容器之间也是可以共享数据的
11.1 容器数据卷挂载命令
Docker run -v Docker服务目录:容器目录映射
# -v 挂载卷docker run -it -v /home/lyf:/home centos /bin/bash # 查看容器详情docker inspect centos
列出所有 Docker 卷:
docker volume ls
这会列出所有当前系统中存在的 Docker 卷,包括名称、驱动程序和卷的大小等信息。
查看特定 Docker 卷的详细信息:
docker volume inspect <volume_name>
[root@hcss-ecs-b45b ~]# docker volume inspect portainer_datas
[{"CreatedAt": "2025-01-20T09:57:52+08:00","Driver": "local","Labels": null,"Mountpoint": "/var/lib/docker/volumes/portainer_datas/_data","Name": "portainer_datas","Options": null,"Scope": "local"}
]# 1. CreatedAt:该数据卷的创建时间,
# 2. Driver:表示该数据卷使用的存储驱动是 local,这是 Docker 最常用的存储驱动,数据会存储在 Docker 主机本地。
# 3. Labels:这里显示该数据卷没有设置任何标签。标签可用于对数据卷进行标记和分类,例如可以设置 Labels: {"environment": "production"} 来标识该数据卷是用于生产环境
# 4. Mountpoint: 该数据卷在 Docker 主机上的挂载点,也就是实际存储数据的物理位置。在这个例子中,数据卷 portainer_datas 的数据存储在 Docker 主机的 /var/lib/docker/volumes/portainer_datas/_data 目录下。
# 5. Name:该数据卷的名称,方便对数据卷进行识别和管理,这里名称是 portainer_datas。
# 6. Options::表示该数据卷没有使用任何特殊的存储驱动选项。一些存储驱动可能支持额外的选项,例如设置存储卷的配额、性能参数等
# 7. Scope 该数据卷的范围是 local,意味着这个数据卷仅在本地 Docker 环境中可用,不会跨 Docker 主机共享(与分布式存储卷不同)
删除 Docker 卷:
docker volume rm <volume_name>
这会删除指定名称的 Docker 卷。请注意,只有当没有容器正在使用该卷时,才能成功删除。
删除未使用的 Docker 卷:
docker volume prune
为 Docker 卷添加标签:
docker volume label <volume_name> <label_key>=<label_value>
移除 Docker 卷的标签:
docker volume label rm <volume_name> <label_key>
11.2 匿名卷和具名卷
匿名卷是 Docker 自动创建的卷,它们没有显式指定的名称。 当在 Docker 容器中挂载一个卷但没有指定卷名称时,Docker 会自动创建一个匿名卷。
- 匿名卷的名称是 Docker 自动生成的,对于用户来说是不可见的。
- 匿名卷可以确保数据的持久化,即使容器被删除,数据仍然存储在 Docker 主机上的某个位置。
- 由于没有显式的卷名,管理和维护相对困难,特别是当需要重新使用或迁移数据时。
# 匿名挂载
[root@hcss-ecs-b45b ~]# docker run --name nginx01 -d -v /etc/nginx nginx
b57f748eea5ee8d9944708fa218fdae05535a04160823cc413aad2e63ac14cb2
# 查看卷信息
[root@hcss-ecs-b45b ~]# docker volume ls
DRIVER VOLUME NAME
local 47a7b9b4c08f0efe9a8c2359e07a3a42eb80fbdad4767b9eb0074fa16a4005d7
# 通常匿名挂载的卷路径在/var/lib/docker/volumes/
具名挂载
它具有一个用户指定的名称,相比于匿名卷(由 Docker 自动创建,名称随机),具名卷更容易管理和维护
回顾Portainer章节,运行Portainer可视化界面容器的Docker命令时
# 创建具名卷
docker volume create portainer_datas# 运行Portainer
# 具名卷挂载
docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_datas:/data portainer/portainer
12 数据卷容器
数据卷容器是一种特殊的容器,其主要目的是用来管理和共享数据卷。
它不运行任何应用程序,而是专门为其他容器提供数据卷,其他容器可以挂载该数据卷容器的数据卷,从而实现数据的共享和持久化存储。
12.1 创建一个数据卷容器
docker create --name data_volume_container -v /data_volume busybox
docker create
:这是一个创建容器但不启动容器的 Docker 命令。--name data_volume_container
:为创建的容器指定名称,这里将容器命名为data_volume_container
。-v /data_volume
:创建一个名为/data_volume
的数据卷。busybox
:使用busybox
镜像作为容器的基础镜像,因为busybox
是一个轻量级且包含常用工具的镜像,适合用于创建数据卷容器。
该命令创建了一个名为 data_volume_container
的数据卷容器,并在其中创建了一个名为 /data_volume
的数据卷。这个数据卷容器处于停止状态,但它所包含的数据卷可以被其他容器使用。
12.2 创建新容器使用这个数据卷容器
docker run -d --name nginx01 --volumes-from data_volume_container nginx
docker run -d --name nginx02 --volumes-from data_volume_container nginx# --volumes-from list Mount volumes from the specified container(s)
# 从名为 data_volume_container 的容器中挂载数据卷。
#当你运行 nginx01 和 nginx02 容器时,它们将从 data_volume_container容器 挂载 /data_volume 数据卷。这样,nginx01 和 nginx02 就可以共享 /data_volume 中的数据,它们对 /data_volume 的操作会互相影响,实现了数据的共享和持久化存储。
通过docker inspect 容器 查看详情 发现nginx01 nginx02 data_volume_container的目的挂载路径全部在Docker宿主主机上,且目的路径全部一致,从而实现了多容器数据同步的效果
12.3 使用数据卷容器的优势
1. 数据共享和持久化:
- 多个容器可以共享存储在数据卷容器中的数据卷,即使容器被删除,数据卷中的数据仍然保存在 Docker 主机上,因为数据卷的生命周期独立于容器。
2. 集中管理:
- 数据卷容器可以集中管理多个数据卷,方便多个容器的挂载和使用。例如,在一个复杂的多容器应用程序中,可以使用一个数据卷容器来存储配置文件、共享的静态文件或数据库文件,其他容器可以通过挂载该数据卷容器的数据卷来访问这些数据。
3. 方便维护:
- 对数据卷的备份、迁移和更新操作可以通过数据卷容器进行集中管理,提高了数据管理的便利性。
13 DockerFile
Dockerfile是一种文本文件,用于定义Docker镜像的内容和构建步骤。它包含一系列指令,每个指令代表一个构建步骤,从基础镜像开始,逐步构建出最终的镜像。通过Dockerfile,用户可以精确地描述应用程序运行环境的配置、依赖项安装、文件复制等操作。这使得应用程序的部署和分发变得更加可控和可重复。Dockerfile的内容可以根据需求自定义,允许开发者根据应用程序的特性和需求来灵活配置镜像的构建过程,从而实现高效、可靠的容器化部署。
通过 Dockerfile,可以自动化 Docker 镜像的构建过程,确保构建过程的可重复性和一致性。
# 创建一个DockerFile DockerFile_01
# 基础镜像
FROM centosVOLUME ["V1","V2"]CMD ECHO "=====end====="CMD /bin/bash# 根据DockerFile 去构建镜像
docker build -f DockerFile_01 -t my_centos:1.0 .-f DockerFile的路径
-t IMAGE_NAME:TAG 镜像命名并打上tag标签
13.1 DockerFile脚本命令
前提: 每个保留关键字都必须是大写的; 命令的执行是从上至下的;DockerFile是面向开发的,我们以后要发布项目就需要编写DockerFile将其做成镜像
- 基础镜像选择(FROM)
- FROM指令是Dockerfile的第一条指令,用于指定基础镜像。例如FROM ubuntu:latest,这表示以最新版本的Ubuntu操作系统镜像作为基础,后续的指令将在这个基础镜像上执行。
- 维护者信息(MAINTAINER,已弃用,推荐使用LABEL)
- 旧版本中使用MAINTAINER指令声明镜像的维护者信息,如MAINTAINER your - name <your - email@example.com>。现在推荐使用LABEL指令,如LABEL maintainer = “your - name <your - email@example.com>”,可以提供更丰富的元数据信息。
- 安装软件包(RUN)
- RUN指令用于在构建镜像的过程中执行命令,安装所需的软件包等。例如RUN apt - get update && apt - get install - y nginx,这条指令先更新Ubuntu系统的软件包列表,然后安装Nginx Web服务器。
- 设置工作目录(WORKDIR)
- WORKDIR指令用于指定容器内的工作目录。例如WORKDIR /app,后续的指令如COPY、RUN等如果涉及相对路径,都将以/app作为基准目录。
- 复制文件(COPY)
- COPY指令用于将本地的文件或目录复制到镜像中。例如COPY. /app,它将当前构建上下文目录下的所有文件和目录复制到容器内的/app目录。
- 设置环境变量(ENV)
- ENV指令用于设置环境变量。例如ENV PORT 8080,设置了一个名为PORT的环境变量,值为8080,在容器内的应用程序可以读取这个环境变量来配置端口等信息。
- 暴露端口(EXPOSE)
- EXPOSE指令用于声明容器运行时将监听的端口。例如EXPOSE 80,表示容器内的应用程序将在端口80上监听,不过这只是一个声明,实际要使端口对外可访问,在运行容器时还需要使用-p选项进行端口映射。
- 容器启动命令(CMD或ENTRYPOINT)
- CMD指令用于指定容器启动时要执行的默认命令。例如CMD [“nginx”, “-g”, “daemon off;”],容器启动时将运行Nginx并以非守护进程模式运行。ENTRYPOINT指令也用于指定容器启动时执行的命令,但它更常用于设置容器的主入口点,使得容器以类似可执行程序的方式运行。两者有一些区别,CMD可以被docker run命令后的参数覆盖,而ENTRYPOINT则更稳定,通常用于那些需要固定执行逻辑的场景。
13.2 Net6项目通过Docker发布DockerFile如何编写
# 此階段用於生產環境,或以一般模式從 VS 執行時 (未使用偵錯設定時的預設值)
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
ENV ASPNETCORE_ENVIRONMENT PRODUCTION
# 指定服务器监听的端口为8081
ENV ASPNETCORE_URLS=http://+:8081
COPY . /app
ENTRYPOINT ["dotnet", "DockerFileDemo.dll"]
根据DockerFile构建镜像
docker build -f DockerFile路径 -t net6_demo:2.0 .# -f 指定DockerFile 路径
# -t name:tag 镜像名和tag标识
在
docker build
命令里,.
是一个非常重要的参数,通常将当前执行命令的目录作为构建上下文路径构建上下文:是一个包含了 Docker 构建镜像所需文件和目录的集合。Docker 守护进程会将这个上下文中的所有内容发送到 Docker 引擎,以便在构建过程中使用。例如,当你的
Dockerfile
中使用COPY
或ADD
指令时,这些指令所引用的文件路径就是相对于构建上下文路径的。