docker学习笔记
一、Docker介绍
1.1、什么是docker
Docker是一个开源的应用容器引擎,使用Go语言开发,基于Linux内核的cgroup,namespace,Union FS等技术,对应用进程进行封装隔离,并且独立于宿主机与其他进程,这种运行时封装的状态称为容器。
Docker早期版本实现是基于LXC,并进一步对其封装,包括文件系统、网络互联、镜像管理等方面,极大简化了容器管理。从0.7版本以后开始去除LXC,转为自省研发的libcontainer,从1.11版本开始,进一步为使用runC和containerd。
Docker理念是将应用及依赖包打包到一个可移植的容器中,可发布到任意Linux发行版Docker引擎上。使用沙箱机制运行程序,程序之间相互隔离。
1.2、docker结构体系
Containerd:是一个简单的守护进程,使用runC管理容器。向Docker Engine提供接口。
Shim:只负责管理一个容器。
runC:是一个轻量级的工具,只用来运行容器。
- Docker Client:客户端
- Docker Daemon:守护进程
- Docker Images:镜像
- Docker Container:容器
- Docker Registry:镜像仓库
1.3、docker内部组件
Namespaces
1 | 命名空间,Linux内核提供的一种对进程资源隔离的机制,例如进程、网络、挂载点等资源。 |
CGroup
1 | 控制组,Linux内核提供的一种限制进程资源的机制;例如CPU、内存等资源。 |
UnionFS
1 | 联合文件系统,支持将不同位置的目录挂载到同一虚拟文件系统,形成一种分层的模型。 |
1.4、什么是容器
- 对软件和其依赖的标准化打包
- 应用之间相互隔离
- 共享同一个OS Kernel
- 可以运行在很多主流操作系统上
1.5、容器和虚拟机的区别
以KVM为例与Docker对比
启动时间
1 | Docker妙级启动,KVM分钟级启动。 |
轻量级
1 2 3 | 容器镜像带下通常以M为单位,虚拟机以G为单位。 容器资源占用小,要比虚拟机部署更快捷。 |
性能
1 2 | 容器共享宿主机内核,系统级虚拟化,占用资源少,没有Hypervisor层开销,容器性能基本接近物理机; 虚拟机需要Hypervisior层支持,虚拟化一些设备,具备完整的GuestOS,虚拟化开销大,因而降低性能,没有容器性能好。 |
安全性
1 | 由于共享宿主机内核,只是进程级隔离,因此隔离性和稳定性不如虚拟机,容器具有一定权限访问宿主机内核,存在一定安全隐患。 |
使用要求
1 2 | KVM基于硬件的完全虚拟化、需要赢家CPU虚拟化技术支持; 容器共享所主机内核,可运行在主流的Linux发行版,不用考虑CPU是否支持虚拟化技术。 |
1.6、docker应用场景
•应用程序打包和发布
•应用程序隔离
•持续集成
•微服务部署
•快速搭建测试环境
•提供PaaS产品(平台即服务)
二、docker安装
2.1、关闭防火墙
1 2 | systemctl stop firewalld systemctl disable firewalld |
2.2、关闭selinux
1 2 3 4 5 6 | vim /etc/selinux/config SELINUX=disabled #设置为disabled reboot #重启服务器 # 查看selinux状态 [root@server04 ~] # getenforce Disabled |
2.3、安装所需要的包
1 | yum install -y yum-utils device-mapper-persistent-data lvm2 |
2.4、配置yum源
1 | yum-config-manager --add-repo https: //download .docker.com /linux/centos/docker-ce .repo |
2.5、安装docker-ce
1 | yum install docker-ce -y |
2.6、启动
1 2 3 4 5 | systemctl start docker # 加入开机启动 systemctl enable docker |
2.7、运行hello-world
1 | docker run hello-world |
2.8、查看docker版本
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | [root@server04 ~] # docker info Client: Docker Engine - Community Version: 24.0.6 Context: default Debug Mode: false Plugins: buildx: Docker Buildx (Docker Inc.) Version: v0.11.2 Path: /usr/libexec/docker/cli-plugins/docker-buildx compose: Docker Compose (Docker Inc.) Version: v2.21.0 Path: /usr/libexec/docker/cli-plugins/docker-compose Server: Containers: 2 Running: 0 Paused: 0 Stopped: 2 Images: 2 Server Version: 24.0.6 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Using metacopy: false Native Overlay Diff: true userxattr: false Logging Driver: json- file Cgroup Driver: cgroupfs Cgroup Version: 1 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json- file local logentries splunk syslog Swarm: inactive Runtimes: runc io.containerd.runc.v2 Default Runtime: runc Init Binary: docker-init containerd version: 61f9fd88f79f081d64d6fa3bb1a0dc71ec870523 runc version: v1.1.9-0-gccaecfc init version: de40ad0 Security Options: seccomp Profile: builtin Kernel Version: 3.10.0-1160.90.1.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 4 Total Memory: 3.682GiB Name: server04 ID: be595f37-af7c-486d-aca2-76c3590143f7 Docker Root Dir: /var/lib/docker Debug Mode: false Experimental: false Insecure Registries: 127.0.0.0 /8 Registry Mirrors: https: //registry .docker-cn.com/ Live Restore Enabled: false |
2.9、查看运行了哪些docker
1 2 3 4 5 | docker run -it nginx <<== -it前台运行、再打开一个终端用于查看 [root@server04 ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5e17bb7f5848 nginx "/docker-entrypoint.…" 35 seconds ago Up 33 seconds 80 /tcp modest_wescoff |
2.10、查看容器信息
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | [root@server04 ~] # docker inspect 5e17bb7f5848 [ { "Id" : "5e17bb7f58482e8921b45559f2ffddb45f3ad192644e5fe50aaac8f2f055cc2c" , "Created" : "2023-09-25T16:11:02.449798245Z" , "Path" : "/docker-entrypoint.sh" , "Args" : [ "nginx" , "-g" , "daemon off;" ], "State" : { "Status" : "running" , "Running" : true , "Paused" : false , "Restarting" : false , "OOMKilled" : false , "Dead" : false , "Pid" : 2566, "ExitCode" : 0, "Error" : "" , "StartedAt" : "2023-09-25T16:11:03.170447828Z" , "FinishedAt" : "0001-01-01T00:00:00Z" }, "Image" : "sha256:61395b4c586da2b9b3b7ca903ea6a448e6783dfdd7f768ff2c1a0f3360aaba99" , "ResolvConfPath" : "/var/lib/docker/containers/5e17bb7f58482e8921b45559f2ffddb45f3ad192644e5fe50aaac8f2f055cc2c/resolv.conf" , "HostnamePath" : "/var/lib/docker/containers/5e17bb7f58482e8921b45559f2ffddb45f3ad192644e5fe50aaac8f2f055cc2c/hostname" , "HostsPath" : "/var/lib/docker/containers/5e17bb7f58482e8921b45559f2ffddb45f3ad192644e5fe50aaac8f2f055cc2c/hosts" , "LogPath" : "/var/lib/docker/containers/5e17bb7f58482e8921b45559f2ffddb45f3ad192644e5fe50aaac8f2f055cc2c/5e17bb7f58482e8921b45559f2ffddb45f3ad192644e5fe50aaac8f2f055cc2c-json.log" , "Name" : "/modest_wescoff" , "RestartCount" : 0, "Driver" : "overlay2" , "Platform" : "linux" , "MountLabel" : "" , "ProcessLabel" : "" , "AppArmorProfile" : "" , "ExecIDs" : null, "HostConfig" : { "Binds" : null, "ContainerIDFile" : "" , "LogConfig" : { "Type" : "json-file" , "Config" : {} }, "NetworkMode" : "default" , "PortBindings" : {}, "RestartPolicy" : { "Name" : "no" , "MaximumRetryCount" : 0 }, "AutoRemove" : false , "VolumeDriver" : "" , "VolumesFrom" : null, "ConsoleSize" : [ 30, 96 ], "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" : null, "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" ], "ReadonlyPaths" : [ "/proc/bus" , "/proc/fs" , "/proc/irq" , "/proc/sys" , "/proc/sysrq-trigger" ] }, "GraphDriver" : { "Data" : { "LowerDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba-init/diff:/var/lib/docker/overlay2/4f78ae5f917ca08bbde77f1ad187042791389068f8263be9221aef4f9a3e09aa/diff:/var/lib/docker/overlay2/7bbeb264406af998971a0ec5938723699549c21762aae769666fdb49aa6651bc/diff:/var/lib/docker/overlay2/6017b041b54f72167c4b957c71a974c1d702e3219cc39e2f2f65c4f00204658a/diff:/var/lib/docker/overlay2/87e2982f0891eaac69d78567aa1e9f2a8febb3b839af2bf7998920f440c9907d/diff:/var/lib/docker/overlay2/ce8dddff3e864f83ab6dd2a171a361dad987cdc65ad9571216002ef1d50f3e88/diff:/var/lib/docker/overlay2/09530dcf8710fdbc06635f6e9f4e64acf3d2cd790d844124752e60b226c6a125/diff:/var/lib/docker/overlay2/4eb51cab29daf0a9426941427e54e4b6e9257678e1358238b13a16f88348a447/diff" , "MergedDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba/merged" , "UpperDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba/diff" , "WorkDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba/work" }, "Name" : "overlay2" }, "Mounts" : [], "Config" : { "Hostname" : "5e17bb7f5848" , "Domainname" : "" , "User" : "" , "AttachStdin" : true , "AttachStdout" : true , "AttachStderr" : true , "ExposedPorts" : { "80/tcp" : {} }, "Tty" : true , "OpenStdin" : true , "StdinOnce" : true , "Env" : [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" , "NGINX_VERSION=1.25.2" , "NJS_VERSION=0.8.0" , "PKG_RELEASE=1~bookworm" ], "Cmd" : [ "nginx" , "-g" , "daemon off;" ], "Image" : "nginx" , "Volumes" : null, "WorkingDir" : "" , "Entrypoint" : [ "/docker-entrypoint.sh" ], "OnBuild" : null, "Labels" : { "maintainer" : "NGINX Docker Maintainers <docker-maint@nginx.com>" }, "StopSignal" : "SIGQUIT" }, "NetworkSettings" : { "Bridge" : "" , "SandboxID" : "f4c582778308d596719d33523236eac2ef77457d181daea2e5fbed907e855eee" , "HairpinMode" : false , "LinkLocalIPv6Address" : "" , "LinkLocalIPv6PrefixLen" : 0, "Ports" : { "80/tcp" : null }, "SandboxKey" : "/var/run/docker/netns/f4c582778308" , "SecondaryIPAddresses" : null, "SecondaryIPv6Addresses" : null, "EndpointID" : "cb440654ecf1609aeea7fbd6e13c4f0d51280f5d8ee4ff2330f1a320246f7b06" , "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, "NetworkID" : "3aca20bdb238ca54726173bf0e92d3973b3f5cb95053800b683aa2639e99a9de" , "EndpointID" : "cb440654ecf1609aeea7fbd6e13c4f0d51280f5d8ee4ff2330f1a320246f7b06" , "Gateway" : "172.17.0.1" , "IPAddress" : "172.17.0.2" , "IPPrefixLen" : 16, "IPv6Gateway" : "" , "GlobalIPv6Address" : "" , "GlobalIPv6PrefixLen" : 0, "MacAddress" : "02:42:ac:11:00:02" , "DriverOpts" : null } } } } ]< /docker-maint @nginx.com> |
1 2 3 4 5 6 7 8 9 10 | [root@server04 ~] # curl -I 172.17.0.2 HTTP /1 .1 200 OK Server: nginx /1 .25.2 Date: Mon, 25 Sep 2023 16:14:01 GMT Content-Type: text /html Content-Length: 615 Last-Modified: Tue, 15 Aug 2023 17:03:04 GMT Connection: keep-alive ETag: "64dbafc8-267" Accept-Ranges: bytes |
2.11、进入容器
1 2 3 4 5 6 7 | [root@server04 ~] # docker exec -it 5e17bb7f5848 bash root@5e17bb7f5848:/ # ls bin docker-entrypoint.d home lib64 mnt root srv usr boot docker-entrypoint.sh lib libx32 opt run sys var dev etc lib32 media proc sbin tmp root@5e17bb7f5848:/ # exit exit |
三、镜像管理
3.1、镜像是什么
- 一个分层存储的文件
- 一个软件的环境
- 一个镜像可以创建N个容器
- 一种标准化的交付
- 一个不包含Linux内核而又精简的Linux操作系统
镜像不是一个单一的文件,而是有多层构成。我们可以通过docker history <ID/NAME>查看镜像中各层内容及大小,每层对应着Dockerfile中的一条指令。Docker镜像默认存储在/var/lib/docker/<storage-driver>中。
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 39 40 41 42 | [root@server04 ~] # docker history nginx IMAGE CREATED CREATED BY SIZE COMMENT 61395b4c586d 5 days ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B 5 days ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT 0B 5 days ago /bin/sh -c #(nop) EXPOSE 80 0B 5 days ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-entr… 0B 5 days ago /bin/sh -c #(nop) COPY file:9e3b2b63db9f8fc7… 4.62kB 5 days ago /bin/sh -c #(nop) COPY file:57846632accc8975… 3.02kB 5 days ago /bin/sh -c #(nop) COPY file:3b1b9915b7dd898a… 298B 5 days ago /bin/sh -c #(nop) COPY file:caec368f5a54f70a… 2.12kB 5 days ago /bin/sh -c #(nop) COPY file:01e75c6dd0ce317d… 1.62kB 5 days ago /bin/sh -c set -x && groupadd --system -… 112MB 5 days ago /bin/sh -c #(nop) ENV PKG_RELEASE=1~bookworm 0B 5 days ago /bin/sh -c #(nop) ENV NJS_VERSION=0.8.0 0B 5 days ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.25.2 0B 5 days ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B 5 days ago /bin/sh -c #(nop) CMD ["bash"] 0B 5 days ago /bin/sh -c #(nop) ADD file:a1398394375faab8d… 74.8MB [root@server04 ~] # cd /var/lib/docker [root@server04 /var/lib/docker ] # ls buildkit engine- id network plugins swarm volumes containers image overlay2 runtimes tmp [root@server04 /var/lib/docker ] # cd overlay2/ [root@server04 /var/lib/docker/overlay2 ] # ls 09530dcf8710fdbc06635f6e9f4e64acf3d2cd790d844124752e60b226c6a125 12f1fd113a660071b93a2a2fa91ab50fd1be168ef6130ab563fb0cb3dc88bd40 13c917e7c0cf4484a29961b08161654dbc20848becd993cb4d07105d7e8dd7a0 13c917e7c0cf4484a29961b08161654dbc20848becd993cb4d07105d7e8dd7a0-init 2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba 2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba-init 417fab199b09d8d1114518d0ae8e28890221cbb13b7066eeaac09b14bfec6b47 4eb51cab29daf0a9426941427e54e4b6e9257678e1358238b13a16f88348a447 4f78ae5f917ca08bbde77f1ad187042791389068f8263be9221aef4f9a3e09aa 6017b041b54f72167c4b957c71a974c1d702e3219cc39e2f2f65c4f00204658a 7bbeb264406af998971a0ec5938723699549c21762aae769666fdb49aa6651bc 8381dcc4c841c5e9c156e709a55aec14db57fecc48f62bac8dbb76806048f4a2 8381dcc4c841c5e9c156e709a55aec14db57fecc48f62bac8dbb76806048f4a2-init 87e2982f0891eaac69d78567aa1e9f2a8febb3b839af2bf7998920f440c9907d backingFsBlockDev ce8dddff3e864f83ab6dd2a171a361dad987cdc65ad9571216002ef1d50f3e88 l [root@server04 /var/lib/docker/overlay2 ] # |
3.2、镜像从哪里来
Docker Hub是由Docker公司负责维护的公共注册中心,包含大量的容器镜像,Docker工具默认从这个公共镜像库下载镜像。地址:https://hub.docker.com/explore
3.3、配置进镜像加速器
1 2 3 4 5 | https: //www .daocloud.io /mirror curl -sSL https: //get .daocloud.io /daotools/set_mirror .sh | sh -s http: //f1361db2 .m.daocloud.io systemctl restart docker |
3.4、镜像与容器的联系
如图,容器其实是在镜像的最上面加了一层读写层,在运行容器里文件改动时,会先从镜像里面要写的文件复制到容器自己的文件系统中(读写层)。
如果容器删除了,最上面的读写层也就被删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高磁盘利用率。
若想持久化这些改动,可以通过docker commit将容器保存成一新的镜像。
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 | [root@server04 ~] # docker run -itd nginx 4a29bf71d65abab063f697c7101786ad09be2823e4ade796c4c10cc4eaec0bb0 [root@server04 ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4a29bf71d65a nginx "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80 /tcp beautiful_lichterman ac118f15419c nginx "/docker-entrypoint.…" 33 seconds ago Up 32 seconds 80 /tcp quizzical_wescoff 5e17bb7f5848 nginx "/docker-entrypoint.…" 13 minutes ago Up 13 minutes 80 /tcp modest_wescoff [root@server04 ~] # docker exec -it 5e17bb7f5848 bash root@5e17bb7f5848:/ # ls bin dev docker-entrypoint.sh home lib32 libx32 mnt proc run srv tmp var boot docker-entrypoint.d etc lib lib64 media opt root sbin sys usr root@5e17bb7f5848:/ # touch nginx.txt root@5e17bb7f5848:/ # exit exit [root@server04 ~] # docker inspect 5e17bb7f5848 ... "GraphDriver" : { "Data" : { "LowerDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba-init/diff:/var/lib/docker/overlay2/4f78ae5f917ca08bbde77f1ad187042791389068f8263be9221aef4f9a3e09aa/diff:/var/lib/docker/overlay2/7bbeb264406af998971a0ec5938723699549c21762aae769666fdb49aa6651bc/diff:/var/lib/docker/overlay2/6017b041b54f72167c4b957c71a974c1d702e3219cc39e2f2f65c4f00204658a/diff:/var/lib/docker/overlay2/87e2982f0891eaac69d78567aa1e9f2a8febb3b839af2bf7998920f440c9907d/diff:/var/lib/docker/overlay2/ce8dddff3e864f83ab6dd2a171a361dad987cdc65ad9571216002ef1d50f3e88/diff:/var/lib/docker/overlay2/09530dcf8710fdbc06635f6e9f4e64acf3d2cd790d844124752e60b226c6a125/diff:/var/lib/docker/overlay2/4eb51cab29daf0a9426941427e54e4b6e9257678e1358238b13a16f88348a447/diff" , "MergedDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba/merged" , "UpperDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba/diff" , "WorkDir" : "/var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba/work" }, "Name" : "overlay2" ... [root@server04 ~] # cd /var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba [root@server04 /var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba ] # ls diff link lower merged work [root@server04 /var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba ] # ls diff <<==与镜像差异 etc nginx.txt root run var [root@server04 /var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba ] # ls merged/ <<==Nginx工作的数据驱动存储 bin dev docker-entrypoint.sh home lib32 libx32 mnt opt root sbin sys usr boot docker-entrypoint.d etc lib lib64 media nginx.txt proc run srv tmp var [root@server04 /var/lib/docker/overlay2/2f69c7685d3203344082158551d1b6a5800836b31e5170747ba904178939daba ] # ls work work |
3.5、管理镜像常用命令
docker image --help
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | 当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。 #列出镜像列表 [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 61395b4c586d 2 weeks ago 187MB ubuntu 14.04 13b66b487594 2 years ago 197MB ubuntu 15.10 9b9cb95443b5 7 years ago 137MB 各个选项说明: REPOSITORY:表示镜像的仓库源 TAG:镜像的标签 IMAGE ID:镜像ID CREATED:镜像创建时间 SIZE:镜像大小 #docker image ls 命令列表中只显示顶层镜像。-a 参数可以显示包括中间层在内的所有镜像 docker image ls -a #根据仓库名列出镜像 docker image ls nginx #根据某个特定标签列出镜像 docker image ls nginx:v2 #mongo:3.2 之后建立的镜像 before 之前 docker image ls -f since=mongo:3.2 #列出标签是dev的镜像 docker image ls -f label=dev #根据名称和标签匹配并只显示id docker images -q -f reference= 'eshop/*:dev' #查看镜像、容器、数据卷所占的空间大小 docker system df 同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。 #运行镜像 [root@docker ~]# docker run -i -t ubuntu:15.10 /bin/bash root@f08f4fafc38b:/# #运行镜像并进入shell 退出后删除镜像 docker run -it --rm ubuntu:15.10 /bin/bash 运行镜像,--name 给镜像取一个名字 -d 后台运行模式 -p 镜像端口映射 docker run --name webserver -d -p 80:80 nginx #查看镜像历史 docker image history nginx #查看镜像详细信息 docker image inspect nginx 如果不指定一个镜像的版本标签,例如只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。 当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果想预先下载这个镜像,可以使用 docker pull 命令来下载它。 [root@docker ~]# docker run -i -t ubuntu:13.10 /bin/bash #查找镜像 [root@docker ~]# docker search httpd NAME DESCRIPTION STARS OFFICIAL AUTOMATED httpd The Apache HTTP Server Project 4559 [OK] clearlinux/httpd httpd HyperText Transfer Protocol (HTTP) ser… 5 paketobuildpacks/httpd 0 vulhub/httpd 0 jitesoft/httpd Apache httpd on Alpine linux. 0 openquantumsafe/httpd Demo of post-quantum cryptography in Apache … 1 wodby/httpd 0 avenga/httpd- static 0 dockette/httpdump 0 betterweb/httpd 0 dockette/apache Apache / HTTPD 1 [OK] centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 46 manageiq/httpd Container with httpd, built on CentOS for Ma… 1 [OK] centos/httpd-24-centos8 3 dockerpinata/httpd 1 19022021/httpd-connection_test This httpd image will test the connectivity … 0 publici/httpd httpd:latest 1 [OK] centos/httpd 36 [OK] httpdocker/kubia 0 e2eteam/httpd 0 manasip/httpd 0 httpdss/archerysec ArcherySec repository 0 [OK] solsson/httpd-openidc mod_auth_openidc on official httpd image, ve… 2 [OK] patrickha/httpd-err 0 hypoport/httpd-cgi httpd-cgi 2 [OK] 说明: NAME: 镜像仓库源的名称 DESCRIPTION: 镜像的描述 OFFICIAL: 是否 docker 官方发布 stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。 AUTOMATED: 自动构建。 #拉取镜像 [root@docker ~]# docker pull centos/httpd-24-centos8 Using default tag: latest latest: Pulling from centos/httpd-24-centos8 3c72a8ed6814: Pull complete 42c269fe6f7b: Pull complete afdf2ecdaa2f: Pull complete 07a0da26acf9: Pull complete 74241943e2c2: Pull complete a1d926117d46: Pull complete 9e6c9d2db631: Pull complete a33035987d8c: Pull complete eefe613be3f4: Pull complete Digest: sha256:aba4d65d2949f6228e5f7fd34274b2fa5d16cdd62acf7b82ed00caaac25ca9ec Status: Downloaded newer image for centos/httpd-24-centos8:latest docker.io/centos/httpd-24-centos8:latest #根据ID删除镜像 [root@docker ~]# docker rmi 13b66b487594 Untagged: ubuntu:14.04 Untagged: ubuntu@sha256:64483f3496c1373bfd55348e88694d1c4d0c9b660dee6bfef5e12f43b9933b30 Deleted: sha256:13b66b487594a1f2b75396013bc05d29d9f527852d96c5577cc4f187559875d0 Deleted: sha256:e08f4f554d8df6b04f441fcdfe207b6314d3c709daa2b1ef66f79bbfb529b8c4 Deleted: sha256:c28d0c854fd56736ef4456e3c1c4276a28159751dc13fd1b340bd38d69473f7e Deleted: sha256:f2fa9f4cf8fd0a521d40e34492b522cee3f35004047e617c75fadeb8bfd1e6b7 #根据标签tag删除镜像 [root@docker ~]# docker rmi centos/httpd-24-centos8:latest Untagged: centos/httpd-24-centos8:latest Untagged: centos/httpd-24-centos8@sha256:aba4d65d2949f6228e5f7fd34274b2fa5d16cdd62acf7b82ed00caaac25ca9ec Deleted: sha256:7d2fe0e482baf01e8a54f6c633bb2b5a89b3f35d278458c5ed73f3fdcc5646aa Deleted: sha256:84474b4898d74c3a477245937d64fd2d1bb444738bc6df3d6dbd0ba6b0a459be Deleted: sha256:23b95c18cc98e43d22a8f295828b50a72074e66727106087cd472f23a131a646 Deleted: sha256:5c1a43152895b59cb74d7fb2b9e6a13e0ff13129002efc22c63f22ff5c1b8b11 Deleted: sha256:4cfbed885163f44e46a4d1d1c2d5a7f353ada11fe2b5e6614741e04194fcdbae Deleted: sha256:2ce53b62d06209cad287d49a36d610dcae828073c7092301241e351c5124eaf3 Deleted: sha256:0199c35044b8a78f369a09056b722cdcc44c6da3be4100e19debb8e57c056ea0 Deleted: sha256:aa6801f0b6ec2aa2e2f019ece4a2d85db6e313b4d7ac66ef5a60957a2b35ea84 Deleted: sha256:d0bfbee18a9738b263b43b7ccd74ca40e55fe4b69dd4bbcecf70f7deec979b90 Deleted: sha256:291f6e44771a7b4399b0c6fb40ab4fe0331ddf76eda11080f052b003d96c7726 #强制删除镜像(当一个镜像下面运行的有容器时,如果需要删除可以使用-f进行强制删除) [root@docker ~]# docker rmi -f 7f020f7bf345 Untagged: ubuntu:13.10 Untagged: ubuntu@sha256:403105e61e2d540187da20d837b6a6e92efc3eb4337da9c04c191fb5e28c44dc Deleted: sha256:7f020f7bf34554411031ec0d4f2ab46a2976dad403e1c26bc21dc1bf4c48c8aa #根据ID删除镜像,一般取前3个字符或以上就可以了 docker rmi af34 #过滤删除命令。删除所有仓库名为 nginx 的镜像 docker rmi $(docker image ls -q nginx) docker rmi $(docker image ls -q -f before=nginx:v2) docker rmi $(docker images -q -f reference= 'eshop/*:dev' ) //-f #删除虚悬镜像 docker rmi prune 给镜像打tag docker tag1 centos centos:v6.7 //给镜像打标签 tag1 #更新镜像 更新镜像之前,需要使用镜像来创建一个容器。 在运行的容器内使用 apt- get update 命令进行更新。 [root@docker ~]# docker run -t -i ubuntu:15.10 /bin/bash root@f88b5f611d99:/# apt- get update Ign http: //archive.ubuntu.com wily InRelease Ign http: //archive.ubuntu.com wily-updates InRelease ...... root@f88b5f611d99:/# exit exit 在完成操作之后,输入 exit 命令来退出这个容器。 此时 ID 为 f88b5f611d99 的容器,是按我们的需求更改的容器。我们可以通过命令 docker commit 来提交容器副本。 [root@docker ~]# docker commit -m= "has update" -a= "runoob" f88b5f611d99 runoob/ubuntu:v2 sha256:a82e7cf89e79d63e5854124961bcf266a2cb678a534d3586bfb0e3213fcbf2bc 各个参数说明: -m: 提交的描述信息 -a: 指定镜像作者 e218edb10161:容器 ID runoob/ubuntu:v2: 指定要创建的目标镜像名 我们可以使用 docker images 命令来查看我们的新镜像 runoob/ubuntu:v2: [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE runoob/ubuntu v2 a82e7cf89e79 58 seconds ago 137MB nginx latest 61395b4c586d 2 weeks ago 187MB centos latest 5d0da3dc9764 2 years ago 231MB centos/httpd-24-centos8 latest 7d2fe0e482ba 3 years ago 428MB ubuntu 15.10 9b9cb95443b5 7 years ago 137MB |
四、容器管理
4.1、容器的使用
docker container --help
docker container run --help
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | #查看所有容器 docker ps -a #输出一个 'Hello World'之后终止容器 docker run centos /bin/echo 'Hello World' #启动一个bash端,允许用户进行交互,-t 让Docker分配一个伪终端(pesudo-tty)并绑定到容器的标准输入上,-i 让容器的标准输入保持打开 docker run -t -i centos /bin/bash # -d 在后台运行 docker run -d centos /bin/sh -c "while true;do echo 11;sleep 1; done" 提示:可以用 docker logs 查看输出的结果 查看容器本身的信息 #查看容器信息 docker container ls docker container ls -a 查看容器层改变 docker diff name #终止一个运行中的容器 [root@docker ~]# docker container stop 13cc1a58c5cc 13cc1a58c5cc #可以查看容器终止的状态信息 docker container ls -a #启动一个已经终止的容器 [root@docker ~]# docker start 13cc1a58c5cc 13cc1a58c5cc #重启容器 [root@docker ~]# docker container restart 13cc1a58c5cc 13cc1a58c5cc 进入容器 docker attach 或 docker exec #查看正在运行的容器 docker container ls #进入容器 [root@docker ~]# docker attach 13cc1a58c5cc root@13cc1a58c5cc:/# 注意:如果从这个容器退出,会导致容器的停止。 [root@docker ~]# docker exec -it 8354c9670c9d /bin/bash [root@8354c9670c9d /]# exit exit #-i 这个参数没有分配伪终端但是保持了标准输出,-t 分配一个伪终端 exec与attach两者区别:attach 不会启动新的进程,用exit退出容器跟着停止。exec启动新的进程,exit退出容器不会停止。 #导出容器 [root@docker ~]# docker export f08f4fafc38b > ububtu:15.10.tar #本地导入容器快照 [root@docker ~]# cat ububtu:15.10.tar |docker import - test/ubuntu:v1 sha256:1111cd1ceaf29353a1f712ca4475862627dc7e40f9d93f7ca23b4efc5410dcb6 #也可以通过指定 URL 或者某个目录来导入,例如: $ docker import http: //example.com/exampleimage.tgz example/imagerepo #从容器内拷贝文件到主机上 (注:如果是在容器内,需要exit先切换到宿主机上) docker cp 容器id:容器内路径 目的主机路径 (例如:docker cp 123123:/data/test.txt /data id为123123的容器,将/data/test.txt文件拷贝到宿主机/data目录下) #删除一个处于终止状态的容器 [root@docker ~]# docker rm 13cc1a58c5cc 13cc1a58c5cc 提示:如果要删除一个运行中的容器,需要添加参数 -f 参数。 这时,docker 会发送 SIGKILL 信号给容器。 清理所有终止状态的容器 #查看所有已经创建包括终止状态的容器 [root@docker ~]# docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8354c9670c9d centos "/bin/sh -c 'while t…" 17 minutes ago Up 17 minutes peaceful_stonebraker f88b5f611d99 ubuntu:15.10 "/bin/bash" 53 minutes ago Exited (100) 51 minutes ago nostalgic_cori 9eb8b17b5755 7f020f7bf345 "/bin/bash" About an hour ago Exited (0) About an hour ago clever_darwin f08f4fafc38b ubuntu:15.10 "/bin/bash" About an hour ago Exited (0) About an hour ago angry_matsumoto #清除所有的容器 [root@docker ~]# docker container prune WARNING! This will remove all stopped containers. Are you sure you want to continue ? [y/N] y Deleted Containers: f88b5f611d99bf12b8a0280c9a5711ae71097a7672e033b913b9d86310da6909 9eb8b17b575500981a01ecbbae77f607d3c50500df6efd4ed9bbc1d4e703b118 f08f4fafc38b5742c637be455e2889583ed330595954afa4264699c2948f71d0 Total reclaimed space: 30B #再次查看 [root@docker ~]# docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8354c9670c9d centos "/bin/sh -c 'while t…" 17 minutes ago Up 17 minutes peaceful_stonebraker 运行一个web应用 #拉取镜像 docker pull training/webapp #启动 docker run -d -P training/webapp python app.py 参数说明: -d:让容器在后台运行。 -P:将容器内部使用的网络端口随机映射到我们使用的主机上。 #查看 [root@docker ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f53008dcc18b training/webapp "python app.py" 10 seconds ago Up 9 seconds 0.0.0.0:32768->5000/tcp, :::32768->5000/tcp gracious_rubin 访问: http: //192.168.100.60:32768/ 也可以通过-p来设置端口 #使用 -p 来指定容器80端口绑定到主机81端口 [root@docker ~]# docker run -d -p 81:80 nginx 6931eab5f5acfbb459c5335df4e96e93f55a5007350eed75f3018f37340de584 #查看 [root@docker ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6931eab5f5ac nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:81->80/tcp, :::81->80/tcp heuristic_clarke 参数说明: -P :是容器内部端口随机映射到主机的端口。 -p : 是容器内部端口绑定到指定的主机端口。 另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。 [root@docker ~]# docker run -d -p 127.0.0.1:82:80 nginx dc7d542f02d16b354b0b6db1c179fc8be0563b9cf098a2a3d3de5aa0615cf9d6 上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp。 [root@docker ~]# docker run -d -p 127.0.0.1:82:80/udp nginx 475f75a8f3ec6f739c297eec5779738452fbb10b7bed0901302a0d214601dc61 #查看端口绑定情况 [root@docker ~]# docker port 475f75a8f3ec 80/udp -> 127.0.0.1:82 通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。 使用docker port [name]或docker port [ID]来查看容器的端口映射 [root@docker ~]# docker port f53008dcc18b 5000/tcp -> 0.0.0.0:32768 5000/tcp -> [::]:32768 [root@docker ~]# docker port flamboyant_aryabhata 5000/tcp -> 0.0.0.0:5000 5000/tcp -> [::]:5000 #查看web应用程序日志 docker container logs 8354c9670c9d [root@docker ~]# docker logs -f f53008dcc18b * Running on http: //0.0.0.0:5000/ (Press CTRL+C to quit) 192.168.100.2 - - [09/Oct/2023 15:46:50] "GET / HTTP/1.1" 200 - 192.168.100.2 - - [09/Oct/2023 15:46:50] "GET /favicon.ico HTTP/1.1" 404 - 说明:-f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出。 #停止web容器 [root@docker ~]# docker stop dbfd2cfb772f dbfd2cfb772f #启动web容器 [root@docker ~]# docker start dbfd2cfb772f dbfd2cfb772f #重启web容器 [root@docker ~]# docker restart dbfd2cfb772f dbfd2cfb772f #查询最后一次创建的容器 [root@docker ~]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES dbfd2cfb772f training/webapp "python app.py" 8 minutes ago Up 2 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp flamboyant_aryabhata #强制删除一个正在运行的容器 [root@docker ~]# docker rm -f dbfd2cfb772f dbfd2cfb772f #批量停止容器 [root@docker ~]# docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2) 475f75a8f3ec dc7d542f02d1 f451ab11fc8e 6931eab5f5ac 65ebc6214d29 f53008dcc18b [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 475f75a8f3ec nginx "/docker-entrypoint.…" 6 minutes ago Exited (0) 13 seconds ago gracious_hopper dc7d542f02d1 nginx "/docker-entrypoint.…" 8 minutes ago Exited (0) 13 seconds ago nervous_einstein f451ab11fc8e nginx "/docker-entrypoint.…" 10 minutes ago Exited (0) 13 seconds ago angry_jemison 6931eab5f5ac nginx "/docker-entrypoint.…" 12 minutes ago Exited (0) 13 seconds ago heuristic_clarke 65ebc6214d29 nginx "/docker-entrypoint.…" 15 minutes ago Exited (0) 13 seconds ago practical_napier f53008dcc18b training/webapp "python app.py" 36 minutes ago Exited (137) 3 seconds ago gracious_rubin #批量删除已停止的容器 [root@docker ~]# docker rm $(docker ps -a | awk '{ print $1}' | tail -n +2) 475f75a8f3ec dc7d542f02d1 f451ab11fc8e 6931eab5f5ac 65ebc6214d29 f53008dcc18b #查看 [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 容器连接 #创建一个新容器并重命名为test1 [root@docker ~]# docker run -d -P --name test1 nginx 4f34248cffbed1d6b8e905f431cc99d49391e76ac3d306270458b95ba3b9cc00 #新建名为test-net的网络 [root@docker ~]# docker network create -d bridge test-net 68e34cd65ce4fe02d8b9e28e2c8894780b91ad6cc2c1c067d99627218fbdbe95 #查看网络 [root@docker ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 81aa10007cdf bridge bridge local 61afab7b07f5 host host local b5f2fbc24b81 none null local 68e34cd65ce4 test-net bridge local #创建并运行test2和test3容器并连接到新建的 test-net 网络: [root@docker ~]# docker run -itd --name test2 --network test-net centos /bin/bash 29279c463ed7de9ff7e3510251d301178d195736f05192168c4ea9317f08db00 [root@docker ~]# docker run -itd --name test3 --network test-net centos /bin/bash 3c0803d3df4195b9b37954ad5a9d959ab649607f2076989b53c08ecd8994b9a6 #查看 [root@docker ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3c0803d3df41 centos "/bin/bash" 3 seconds ago Up 2 seconds test3 29279c463ed7 centos "/bin/bash" 26 seconds ago Up 25 seconds test2 4f34248cffbe nginx "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:32770->80/tcp, :::32770->80/tcp test1 下面通过 ping 来证明 test2 容器和 test3 容器建立了互联关系。 [root@29279c463ed7 /]# ping test3 PING test3 (172.18.0.3) 56(84) bytes of data. 64 bytes from test3.test-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.065 ms 64 bytes from test3.test-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.065 ms 64 bytes from test3.test-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.066 ms 64 bytes from test3.test-net (172.18.0.3): icmp_seq=4 ttl=64 time=0.064 ms ^C --- test3 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3051ms rtt min/avg/max/mdev = 0.064/0.065/0.066/0.000 ms |
4.2、容器资源限制
4.2.1、CPU资源控制
cgroups是一个非常强大的linux内核工具,他不仅可以限制被namespace隔离起来的资源,还可以为资源设置权重、计算使用量,操控进程启停等等,所以cgroups(control groups)实现了对资源的配额和度量。
cgroups有四大功能
资源限制: 可以对任务使用的资源总额进行限制
优先级分配: 通过分配cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级。
资源统计: 可以统计系统的资源使用量,如cpu时长,内存用量等。
任务控制: cgroups可以对任务执行挂起,恢复等操作。
设置cpu使用率上限
linux通过CFS(completely fair scheduler,完全公平调度器)来调度各个进程对cpu的使用
我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少cpu时间。
使用 --cpu-period 即可设置调度周期,默认100ms,设置范围为:1ms-1s,对应的 --cpu-period的数值范围是1000~1000000。
使用 --cpu-quota 即可设置在每个周期内容器能使用cpu时间,默认无限制,设置的要求不能小于1ms,也就是–cpu-quota的值必须>=1000.
查看周期限制和cpu配额限制
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 | #启动一个centos镜像 [root@docker ~]# docker run -itd --name test1 centos /bin/bash 3adc4f4f03e2a1f8c1b6ee8e1112c38edb04bd3ee0472e5af7a490c6ccd0afb8 #查看 [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3adc4f4f03e2 centos "/bin/bash" 5 seconds ago Up 4 seconds test1 [root@docker ~]# cd /sys/fs/cgroup/cpu/docker/3adc4f4f03e2a1f8c1b6ee8e1112c38edb04bd3ee0472e5af7a490c6ccd0afb8/ #进入到该容器的限制目录中(3adc4f4f03e2a1f8c1b6ee8e1112c38edb04bd3ee0472e5af7a490c6ccd0afb8为容器ID) [root@docker /sys/fs/cgroup/cpu/docker/3adc4f4f03e2a1f8c1b6ee8e1112c38edb04bd3ee0472e5af7a490c6ccd0afb8]# ls cgroup.clone_children cpuacct.usage cpuacct.usage_percpu_sys cpuacct.usage_user cpu.rt_period_us cpu.stat cgroup.procs cpuacct.usage_all cpuacct.usage_percpu_user cpu.cfs_period_us cpu.rt_runtime_us notify_on_release cpuacct.stat cpuacct.usage_percpu cpuacct.usage_sys cpu.cfs_quota_us cpu.shares tasks #查看每个周期的cpu最大限制时间 [root@docker /sys/fs/cgroup/cpu/docker/3adc4f4f03e2a1f8c1b6ee8e1112c38edb04bd3ee0472e5af7a490c6ccd0afb8]# cat cpu.cfs_quota_us -1 #查看调度周期是多久 [root@docker /sys/fs/cgroup/cpu/docker/3adc4f4f03e2a1f8c1b6ee8e1112c38edb04bd3ee0472e5af7a490c6ccd0afb8]# cat cpu.cfs_period_us 100000 说明: cpu.cfg_period_us: cpu 分配的周期(微秒,所以文件名中用us表示),默认为100000 cpu.cfg_quota_us: 表示该cgroups限制占用的时间(微秒),默认为-1,表示为不限制,如果设为50000,表示占用50000/100000=50%的cpu |
进行cpu压力测试然后修改每个周期的使用cpu的时间,查看cpu使用率
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 | #启动一个容器并设置每个周期cpu执行的时间 [root@docker ~]# docker run -itd --name test2 --cpu-quota 50000 centos /bin/bash 07a39c1247d29275886312fd2e556773f240294be9d43bfffb9149da21554824 #查看 [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 07a39c1247d2 centos "/bin/bash" 22 seconds ago Up 21 seconds test2 3adc4f4f03e2 centos "/bin/bash" 6 minutes ago Up 6 minutes test1 #进入容器 [root@docker ~]# docker exec -it 07a39c1247d2 /bin/bash [root@07a39c1247d2 /]# ls bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var #创建死循环脚本,为了进行cpu压力测试 [root@07a39c1247d2 /]# vi cpu.sh [root@07a39c1247d2 /]# cat cpu.sh #!bin/bash i=0 while true do let i++ done #执行脚本 [root@07a39c1247d2 /]# bash cpu.sh 新开一个窗口,使用top查看这个容器中脚本占的多少的cpu资源 [root@docker ~]# docker exec -it 07a39c1247d2 /bin/bash |
设置cpu资源占用比(设置多个容器时才有效)
Docker通过–cpu-shares指定cpu份额,默认为1024,值为1024的倍数。
在有多个容器竞争CPU时,我们可以设置每个容器能会用的CPU时间比例,这个比例叫做 共享权值。
共享式CPU资源,是按比例切分CPU资源,Docker默认每个容器的权值为1024。如果不指定或将其设置为0,都将使用默认值。
通过-cpu-share并不是cpu资源的绝对数量,而是一个相对的权重值,某个容器最终能分配到的cpu资源取决于它的cpu share占所有容器 cpu share综合的比例。换句话说,通过cpu share可以设置容器使用cpu的优先级。
比如,当前系统上一共运行了两个容器,第一个容器上权重是1024,第二个容器权重是512, 第二个容器启动之后没有运行任何进程,自己身上的512都没有用完,而第一台容器的进程有很多,这个时候它完全可以占用容器二的CPU空闲资源,这就是共享式CPU资源;如果容器二也跑了进程,那么就会把自己的512给要回来,按照正常权重1024:512划分,为自己的进程提供CPU资源。如果容器二不用CPU资源,那容器一就能够把容器二的CPU资源所占用,如果容器二也需要CPU资源,那么就按照比例划分。那么第一个容器会从原来使用整个宿主机的CPU变为使用整个宿主机的CPU的2/3;这就是CPU共享式,也证明了CPU为可压缩性资源。
两个容器设置比例然后压测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | docker run -itd --name c1 --cpu-shares 512 centos docker run -itd --name c2 --cpu-shares 1024 centos #创建两个容器为c1和c2,若只有这两个容器,设置容器的权重,使得c1和c2的cpu资源占比为1/3和2/3 分别进入到c1和c2 容器中,进行压测 #进入容器 docker exec -it 【容器id】 /bin/bash #安装epel源 yum -y install epel-release #安装cpu压力测试工具 yum -y install stress #产生四个进程,每个进程都反复不停的计算随机数的平方根 stress -c 4 #查看容器运行状态(动态更新) docker stats |
设置容器绑定指定的CPU
–cpuset-cpus 是限制容器运行在指定的cpu核心
运行容器运行在哪个CPU核心上,例如主机有4个核心,cpu核心标识为0-3,我们一启动容器,只想让这台容器运行在标识0和3的两个CPU核心上,可以使用cpuset来指定
1 2 3 4 5 6 7 8 9 10 | #启动一个容器,让它只使用内核1和内核3的资源 docker run -itd --name c3 --cpuset-cpus 1,3 centos /bin/bash #进入容器 docker exec -it 【容器id】 /bin/bash #下载压力测试工具,并测试4个核 yum -y install epel-release yum -y install stress stress -c 4 |
4.2.2、内存资源控制
与操作系统类似,容器可以使用的内存包括两部分:物理内存和Swap
Docker通过下面两组参数来控制容器内存的使用量
-m 或 --memory : 设置内存的使用限额, 例如:100MB,2GB
–memory-swap : 设置内存+swap 的使用限额 (这个必须要和–memory一起使用)
正常情况下,–memory-swap 的值包含容器可用内存和可用swap。所以 -m 300m --memory-swap=1g 的含义为:容器可用使用300M的物理内存,并且可以使用700M(1G-300)的swap
如果–memory-swap 设置为0 或者不设置,则容器可以使用的swap大小为-m值的两倍。
如果 --memory-swap 的值和-m 值相同,则容器不能使用swap
如果 --memory-swap值为-1。它表示容器程序使用的内存受限,而可以使用的swap空间不受限制(宿主机有多少swap空间该容器就可以使用多少)
1 2 3 4 5 6 7 8 9 | #允许该容器使用物理内存200M,swap空间为100m [root@docker ~]# docker run -itd --name m1 -m 200m --memory-swap=300M centos /bin/bash 1f99a0263cb566786f24e8f938e0edf6eb8743e2109b88def5c1acfc0b35b6c7 #查看容器使用资源情况 [root@docker ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 1f99a0263cb5 m1 0.00% 1.562MiB / 200MiB 0.78% 586B / 0B 0B / 0B 1 |
4.2.3、磁盘IO配额控制
Block IO 是另一种可以限制容器使用的资源,Block IO 指的是磁盘的读写,docker可通过设置权重,限制bps和iops的方式控制容器读写磁盘的带宽。
限制Block IO
默认情况下,所有容器能平等地读写磁盘,可以通过设置 --blkio-weight 参数来改变容器bliock IO 的优先级。–blkio-weight 与 --cpu-share类似,设置的是相对权重值,默认为500。
1 2 3 | #设置b1容器读写磁盘的带宽是b2容器的两倍 [root@docker ~]# docker run -it --name b1 --blkio-weight 600 centos /bin/bash [root@docker ~]# docker run -it --name b2 --blkio-weight 300 centos /bin/bash |
限制bps和iops进行限制
bps 是 byte per second ,表示每秒读写的数据量。
iops 是 io per second ,表示每秒的输入输出量(或读写次数)
可以通过以下参数控制容器的bps和iops
–device-read-bps,限制读某个设备的bps(数据量)
–device-write-bps,限制写某个设备的bps(数据量)
–device-read-iops,限制读某个设备的iops(次数)
–device-write-iops,限制写某个设备的iops(次数)
对写bps进行限制的测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #创建容器,限制写的数数据量为1mb/s docker run -it --name b5 --device-write-bps /dev/sda:1mb centos /bin/bash #测试是否是写入的1MB/S dd if =/dev/zero of=test. out bs=1M count=10 oflag=direct [root@docker ~]# docker run -it --name b5 --device-write-bps /dev/sda:1mb centos /bin/bash [root@347a164334ad /]# dd if =/dev/zero of=test. out bs=1M count=10 oflag=direct 10+0 records in 10+0 records out 10485760 bytes (10 MB, 10 MiB) copied, 10.0022 s, 1.0 MB/s [root@347a164334ad /]# 清理docker占用的磁盘空间 #可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络 docker system prune -a |
五、容器数据持久化
5.1、将宿主机数据挂载到容器中的三种方式
Docker提供三种方式数据从宿主机挂载到容器中:
- Volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
- bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。
- tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久化存储到任何位置,可以使用tmpfs,同时避免写入容器可写层提高性能。
5.2、Volume
管理卷
1 2 3 4 5 6 7 8 9 10 11 | #创建数据卷 docker volume create nginx-vol #查看所有数据卷 docker volume ls #查看某一数据卷信息 docker volume inspect nginx-vol #清除无主的数据卷 docker volume prune |
用卷创建一个容器
1 2 3 4 | # 新语法 docker run -d --name=nginx- test -- mount src=nginx-vol,dst= /usr/share/nginx/html nginx # 旧语法 docker run -d --name=nginx- test - v nginx-vol: /usr/share/nginx/html nginx |
清理
1 2 3 | docker stop nginx- test docker rm nginx- test docker volume rm nginx-vol |
注意:
1. 如果没有指定卷,自动创建。
2. 建议使用--mount,更通用。
https://docs.docker.com/storage/volumes/#start-a-container-with-a-volume
5.3、Bind Mounts
用卷创建一个容器
1 2 3 4 | # 新语法 docker run -d --name=nginx- test -- mount type =bind,src= /app/wwwroot ,dst= /usr/share/nginx/html nginx # 旧语法 docker run -d --name=nginx- test - v /app/wwwroot : /usr/share/nginx/html nginx |
验证绑定
1 | docker inspect nginx- test |
清理
1 2 | docker stop nginx- test docker rm nginx- test |
注意:
1.2 如果源文件/目录没有存在,不会自动创建,会抛出一个错误。
1.3 如果挂载目标在容器中非空目录,则该目录现有内容将被隐藏
https://docs.docker.com/storage/bind-mounts/#start-a-container-with-a-bind-mount
Volume特点
- 多个运行容器之间共享数据。
- 当容器停止或悲移除时,该卷依然存在。
- 多个容器可以同时挂载相同的卷。
- 当明确删除卷时,卷才会被删除。
- 将容器的数据存储在远程主机或其他存储上
- 将数据从一台Docker主机迁移到另一台时,先停止容器,然后备份卷的目录(/var/lib/docker/volumes)
Bind Mounts特点
- 从主机共享配置文件到容器。默认情况下,挂载主机/etc/resolv.conf到每个容器,提供DNS解析。
- 在Docker主机上的开发环境和容器之间共享源代码。例如,可以将Maven target目录挂载到容器中,每次在Docker主机上构建Maven项目时,容器都可以访问构建的项目包。
- 当Docker主机的文件或目录结构保证与容器所需的绑定挂载一致时
六、容器网络
6.1、docker四种网络模式
bridge
1 2 | -net=bridge 默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。 |
host
1 2 | -net=host 容器不会获得一个独立的network namespace,而是与宿主机共用一个,这就意味着容器不会有自己的网卡信息,而是使用宿主机的。容器除了网络,其他都是隔离的。 |
none
1 2 | -net=none 获取独立的network namespave,但不为容器进行任何网络配置,需要我们手动配置。 |
container
1 2 | -net=container:Name /ID 与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还黑隔离的。 |
自定义网络
1 | 与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名或者主机名容器之间网络通信。 |
6.2、容器网络访问原理
Linux IP信息包过滤原理:
1 2 | Docker主要通过netfilter /iptables 实现网络通信。 iptables由netfilter和iptables组成,netfilter组件是Linux内核集成的信息包过滤系统,它维护一个信息包过滤表,这个表用于控制信息包过滤处理的规则集,而iptables只是一个在用户空间的工具,用于增删改查这个过滤表的规则。 |
容器访问外部
1 2 3 4 | # iptables -t nat -nL Chain POSTROUTING (policy ACCEPT) target prot opt source MASQUERADE all -- 172.17.0.0 /16 destination 0.0.0.0 /0 |
外部访问容器
1 2 3 4 | Chain DOCKER (2 references) target prot opt source DNAT tcp -- 0.0.0.0 /0 destination 0.0.0.0 /0 tcp dpt:88 to:172.18.0.2:80 |
Linux veth pair
veth pair 是成对出现的一种虚拟网络设备接口,一端连着网络协议栈,一端彼此相连。如下图所示:
veth pair将两个网络veth0和veth1连通。
6.3、理解docker0
查看本地IP:
可以看出有3个网络
1 2 3 | lo 127.0.0.1 # 本机回环地址 eth0 172.31.179.120 #虚拟机的ip docker0 172.17.0.1 # docker网桥 |
lo和eth0在我们的虚拟机启动的时候就会创建,但是docker0在我们安装了docker的时候就会创建。docker0用来和虚拟机之间通信。
问题:Docker 是如何处理容器网络访问的?
我们先启动一个 tomcat 容器来说明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [root@docker ~]# docker run -d -p 8081:8080 --name tomcar01 tomcat Unable to find image 'tomcat:latest' locally latest: Pulling from library/tomcat 707e32e9fc56: Pull complete 8e560b9ae2a6: Pull complete 2a200e428b29: Pull complete 3cc43ecfdc12: Pull complete 8ef680a12b1a: Pull complete 9c0d1cf80b70: Pull complete 96c314108863: Pull complete 0a48006c3e0d: Pull complete Digest: sha256:497ab29bd234316118228c2e7c0f307fe6e116d0a7e314add06b4fd6332244ee Status: Downloaded newer image for tomcat:latest 90cbd173e7a663c334ac78d796f2403ada908234da51ea726da02467249fb787 |
启动后再次查看
发现:我们前面查看的时候还是三组网卡,当启动了一个tomcat容器之后,多了一组网卡44: veth67bb05e@if43,而且还是成对的。同样我们再来启动一个tomcar02会又多出一对网卡。
进入了 tomcar01 容器内可以看到 tomcar01 对应的 ip 地址为:172.17.0.2
在宿主机上也可ping通。
说明:tomcar02对应的ip为172.17.0.3,也可以ping通。
结论:我们每启动一个容器,就会多出一对网卡,同时他们被连接到docker0上,而docker0又和虚拟机之间连通。
也可以通过inspect查看。
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | [root@docker ~]# docker network ls NETWORK ID NAME DRIVER SCOPE fbc76cdb2a5c bridge bridge local 61afab7b07f5 host host local b5f2fbc24b81 none null local [root@docker ~]# docker inspect fbc76cdb2a5c [ { "Name" : "bridge" , "Id" : "fbc76cdb2a5cbe08772137e54ec8d76bf284cf5bd6158a369752bff6d80d3b95" , "Created" : "2023-10-10T01:06:33.008195147+08:00" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : null , "Config" : [ { "Subnet" : "172.17.0.0/16" , "Gateway" : "172.17.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : { "90cbd173e7a663c334ac78d796f2403ada908234da51ea726da02467249fb787" : { "Name" : "tomcar01" , "EndpointID" : "035a3468778478c8a2086d380ee274f35af71843ae5ca1da5c1ab5affac30f41" , "MacAddress" : "02:42:ac:11:00:02" , "IPv4Address" : "172.17.0.2/16" , "IPv6Address" : "" }, "a11cd10d4674b7c89b344ed7d02f4e2595adbf8fc6cd546e20910fd5885bdbf6" : { "Name" : "tomcar02" , "EndpointID" : "5c2ca25291a261ee7f4357960cd65fe4108497d0d38280417b7b2579527d6d2f" , "MacAddress" : "02:42:ac:11:00:03" , "IPv4Address" : "172.17.0.3/16" , "IPv6Address" : "" } }, "Options" : { "com.docker.network.bridge.default_bridge" : "true" , "com.docker.network.bridge.enable_icc" : "true" , "com.docker.network.bridge.enable_ip_masquerade" : "true" , "com.docker.network.bridge.host_binding_ipv4" : "0.0.0.0" , "com.docker.network.bridge.name" : "docker0" , "com.docker.network.driver.mtu" : "1500" }, "Labels" : {} } ] |
我们可以抽象为这样一个网络模型。
在这里,我们可以看到Docker0相当于一个路由器的作用,任何一个容器启动默认都是docker0网络。
docker默认会给容器分配一个可用ip,并把它同docke0相连。使用到的就是veth pair技术。
6.4、容器互联--Link
在网络模型图中可以看出,容器和容器之间不能直接连通。
前面我们启动的两个 tomcat 对应的 hosts 如下
1 2 3 4 5 6 7 8 | [root@docker ~]# docker exec -it tomcar01 cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.2 90cbd173e7a6 |
1 2 3 4 5 6 7 8 | [root@docker ~]# docker exec -it tomcar02 cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.3 a11cd10d4674 |
发现:他们的 hosts 中只有各自的ip地址。
但是在实际的工作中,容器使用的是虚拟ip,每次启动ip都会变化,思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?
我们在启动一个tomcar03,使用--link绑定到tomcar02上。然后看它的hosts是什么样的。
1 2 3 4 5 6 7 8 9 10 11 | [root@docker ~]# docker run -d -p 8083:8080 --name tomcar03 --link tomcar02 tomcat 74783a65d3a49f9df5fd91c56ce233196db8fd2d67e03d5ae3326bf04c61ef11 [root@docker ~]# docker exec -it tomcar03 cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.3 tomcar02 a11cd10d4674 172.17.0.4 74783a65d3a4 |
发现:使用了--link,不但有了自己的ip,而且还有了tomcar02的服务名。但是tomcar02中并没有tomcar03的,因为--link是单向的。
这样就实现了容器和容器之间的连通。不需要通过ip地址连通,而是通过服务名就可以。
但是使用--link的方法过时了,我们一般使用自定义网络。
6.5、自定义网络(推荐)
docker0的特点:
它是默认的
域名访问不通
--link 域名通了,但是删了又不行
docker为我们提供了三种网络模式:
1 2 3 4 5 | [root@docker ~]# docker network ls NETWORK ID NAME DRIVER SCOPE fbc76cdb2a5c bridge bridge local 61afab7b07f5 host host local b5f2fbc24b81 none null local |
这其中默认使用的是 bridge,也就是我们的docker0网卡。
在我们启动容器的时候,实际上是如下命令:
1 | docker run -d -P --name tomcat01 --net bridge tomcat |
这个--net是默认的,所以被省略了。
下面我们自定义一个网络 mynet
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 39 40 | # 自定义创建的默认default "bridge" [root@docker ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet 039bfcf9622a95e08937248d5689207fcd2214ed46ae1b847ed62dc12f0ea4ad [root@docker ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 8c0199cdb21d bridge bridge local 61afab7b07f5 host host local 039bfcf9622a mynet bridge local b5f2fbc24b81 none null local [root@docker ~]# docker network inspect mynet [ { "Name" : "mynet" , "Id" : "039bfcf9622a95e08937248d5689207fcd2214ed46ae1b847ed62dc12f0ea4ad" , "Created" : "2023-10-12T20:52:04.491746283+08:00" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : {}, "Config" : [ { "Subnet" : "192.168.0.0/16" , "Gateway" : "192.168.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : {}, "Options" : {}, "Labels" : {} } ] |
使用自定义的网络启动centos
1 2 3 4 5 6 7 8 9 10 11 12 13 | [root@docker ~]# docker run -itd --name centos-net-01 --net mynet centos 5b43e2226bce1abb42a5e51b0c4a66ef1a92209990fc1fd4b7a58a7b50979a5f [root@docker ~]# docker run -itd --name centos-net-02 --net mynet centos 45d2ca1994549008d259f292f6631d0ee83e47ee3de639adbfb9bb7868099eec [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 45d2ca199454 centos "/bin/bash" About a minute ago Up About a minute centos-net-02 5b43e2226bce centos "/bin/bash" About a minute ago Up About a minute centos-net-01 5caa87b2cae7 tomcat "catalina.sh run" 9 minutes ago Up 9 minutes 8080/tcp tomcat-net-02 7036a4190ae1 tomcat "catalina.sh run" 9 minutes ago Up 9 minutes 8080/tcp tomcat-net-01 4ae93d0df394 centos "/bin/bash" 11 minutes ago Up 11 minutes centos01 |
查看网络
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | [root@docker ~]# docker inspect mynet [ { "Name" : "mynet" , "Id" : "039bfcf9622a95e08937248d5689207fcd2214ed46ae1b847ed62dc12f0ea4ad" , "Created" : "2023-10-12T20:52:04.491746283+08:00" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : {}, "Config" : [ { "Subnet" : "192.168.0.0/16" , "Gateway" : "192.168.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : { "45d2ca1994549008d259f292f6631d0ee83e47ee3de639adbfb9bb7868099eec" : { "Name" : "centos-net-02" , "EndpointID" : "3b08e08150506055341ef216e8c469c878bd9411931e73e20a8e48864eff9dc4" , "MacAddress" : "02:42:c0:a8:00:05" , "IPv4Address" : "192.168.0.5/16" , "IPv6Address" : "" }, "5b43e2226bce1abb42a5e51b0c4a66ef1a92209990fc1fd4b7a58a7b50979a5f" : { "Name" : "centos-net-01" , "EndpointID" : "d91c3c2baa1912cbae0f8a3cae36cebcc05d5b4f75d1221d4691e523c674c9f6" , "MacAddress" : "02:42:c0:a8:00:04" , "IPv4Address" : "192.168.0.4/16" , "IPv6Address" : "" }, "5caa87b2cae7400597d8a2eefaf3e85d742cea60d212d6a19fb3d89ec3b21a01" : { "Name" : "tomcat-net-02" , "EndpointID" : "f91f97baa0c331281e6bb5bb9ea7401e9691207da78233e6f4b8c3eca4ad8491" , "MacAddress" : "02:42:c0:a8:00:03" , "IPv4Address" : "192.168.0.3/16" , "IPv6Address" : "" }, "7036a4190ae13d6c37262d61cdef4ac93a200500fee1aafee04b5dfec83a4766" : { "Name" : "tomcat-net-01" , "EndpointID" : "1d6ef9369d097f9b6b3bd2d4cbd08808259d844ff264447a99e1f0b6f0f5850d" , "MacAddress" : "02:42:c0:a8:00:02" , "IPv4Address" : "192.168.0.2/16" , "IPv6Address" : "" } }, "Options" : {}, "Labels" : {} } ] |
测试ping容器名和ip试试,都可以ping通
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 39 40 41 | [root@docker ~]# docker exec -it centos-net-01 ping 192.168.0.5 PING 192.168.0.5 (192.168.0.5) 56(84) bytes of data. 64 bytes from 192.168.0.5: icmp_seq=1 ttl=64 time=0.118 ms 64 bytes from 192.168.0.5: icmp_seq=2 ttl=64 time=0.065 ms 64 bytes from 192.168.0.5: icmp_seq=3 ttl=64 time=0.067 ms 64 bytes from 192.168.0.5: icmp_seq=4 ttl=64 time=0.093 ms ^C --- 192.168.0.5 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3072ms rtt min/avg/max/mdev = 0.065/0.085/0.118/0.024 ms [root@docker ~]# docker exec -it centos-net-02 ping 192.168.0.4 PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data. 64 bytes from 192.168.0.4: icmp_seq=1 ttl=64 time=0.089 ms 64 bytes from 192.168.0.4: icmp_seq=2 ttl=64 time=0.062 ms 64 bytes from 192.168.0.4: icmp_seq=3 ttl=64 time=0.060 ms 64 bytes from 192.168.0.4: icmp_seq=4 ttl=64 time=0.060 ms ^C --- 192.168.0.4 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3098ms rtt min/avg/max/mdev = 0.060/0.067/0.089/0.015 ms [root@docker ~]# docker exec -it centos-net-01 ping centos-net-02 PING centos-net-02 (192.168.0.5) 56(84) bytes of data. 64 bytes from centos-net-02.mynet (192.168.0.5): icmp_seq=1 ttl=64 time=0.092 ms 64 bytes from centos-net-02.mynet (192.168.0.5): icmp_seq=2 ttl=64 time=0.089 ms 64 bytes from centos-net-02.mynet (192.168.0.5): icmp_seq=3 ttl=64 time=0.065 ms 64 bytes from centos-net-02.mynet (192.168.0.5): icmp_seq=4 ttl=64 time=0.099 ms ^C --- centos-net-02 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3075ms rtt min/avg/max/mdev = 0.065/0.086/0.099/0.014 ms [root@docker ~]# docker exec -it centos-net-02 ping centos-net-01 PING centos-net-01 (192.168.0.4) 56(84) bytes of data. 64 bytes from centos-net-01.mynet (192.168.0.4): icmp_seq=1 ttl=64 time=0.065 ms 64 bytes from centos-net-01.mynet (192.168.0.4): icmp_seq=2 ttl=64 time=0.060 ms 64 bytes from centos-net-01.mynet (192.168.0.4): icmp_seq=3 ttl=64 time=0.064 ms 64 bytes from centos-net-01.mynet (192.168.0.4): icmp_seq=4 ttl=64 time=0.066 ms ^C --- centos-net-01 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3055ms rtt min/avg/max/mdev = 0.060/0.063/0.066/0.010 ms |
6.6、网络直连
docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离。
但是在实际的工作中,比如我们部署了mysql使用了一个网段。部署了tomcat使用了另一个网段,两个网段之间肯定是不能相互连通的,但是tomcat和mysql又需要相互连通,我们就要使用网络连通。原理图如下:
网络连通就是将一个容器和一个网段之间的连通。
比如我前面使用的默认docker0的centos01,需要连接到mynet网络。
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | [root@docker ~]# docker exec -it centos01 /bin/bash [root@4ae93d0df394 /]# ip add 1: lo: <loopback,up,lower_up> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 6: eth0@if7: <broadcast,multicast,up,lower_up> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever [root@4ae93d0df394 /]# exit exit [root@docker ~]# docker network connect mynet centos01 [root@docker ~]# docker network inspect mynet [ { "Name" : "mynet" , "Id" : "039bfcf9622a95e08937248d5689207fcd2214ed46ae1b847ed62dc12f0ea4ad" , "Created" : "2023-10-12T20:52:04.491746283+08:00" , "Scope" : "local" , "Driver" : "bridge" , "EnableIPv6" : false , "IPAM" : { "Driver" : "default" , "Options" : {}, "Config" : [ { "Subnet" : "192.168.0.0/16" , "Gateway" : "192.168.0.1" } ] }, "Internal" : false , "Attachable" : false , "Ingress" : false , "ConfigFrom" : { "Network" : "" }, "ConfigOnly" : false , "Containers" : { "45d2ca1994549008d259f292f6631d0ee83e47ee3de639adbfb9bb7868099eec" : { "Name" : "centos-net-02" , "EndpointID" : "3b08e08150506055341ef216e8c469c878bd9411931e73e20a8e48864eff9dc4" , "MacAddress" : "02:42:c0:a8:00:05" , "IPv4Address" : "192.168.0.5/16" , "IPv6Address" : "" }, "4ae93d0df394ff4d56c8ed71c9ffd77fd5a19b94d00c29e8933dc61b1c5db55d" : { "Name" : "centos01" , "EndpointID" : "34facd94a19bd4ef5b82e0ed03c81d2cffb6c81b3a82e5a4bdc030f917367757" , "MacAddress" : "02:42:c0:a8:00:06" , "IPv4Address" : "192.168.0.6/16" , "IPv6Address" : "" }, "5b43e2226bce1abb42a5e51b0c4a66ef1a92209990fc1fd4b7a58a7b50979a5f" : { "Name" : "centos-net-01" , "EndpointID" : "d91c3c2baa1912cbae0f8a3cae36cebcc05d5b4f75d1221d4691e523c674c9f6" , "MacAddress" : "02:42:c0:a8:00:04" , "IPv4Address" : "192.168.0.4/16" , "IPv6Address" : "" }, "5caa87b2cae7400597d8a2eefaf3e85d742cea60d212d6a19fb3d89ec3b21a01" : { "Name" : "tomcat-net-02" , "EndpointID" : "f91f97baa0c331281e6bb5bb9ea7401e9691207da78233e6f4b8c3eca4ad8491" , "MacAddress" : "02:42:c0:a8:00:03" , "IPv4Address" : "192.168.0.3/16" , "IPv6Address" : "" }, "7036a4190ae13d6c37262d61cdef4ac93a200500fee1aafee04b5dfec83a4766" : { "Name" : "tomcat-net-01" , "EndpointID" : "1d6ef9369d097f9b6b3bd2d4cbd08808259d844ff264447a99e1f0b6f0f5850d" , "MacAddress" : "02:42:c0:a8:00:02" , "IPv4Address" : "192.168.0.2/16" , "IPv6Address" : "" } }, "Options" : {}, "Labels" : {} } ]</broadcast,multicast,up,lower_up></loopback,up,lower_up> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [root@docker ~]# docker exec -it centos01 /bin/bash [root@4ae93d0df394 /]# ip add 1: lo: <loopback,up,lower_up> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 6: eth0@if7: <broadcast,multicast,up,lower_up> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever 17: eth1@if18: <broadcast,multicast,up,lower_up> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:c0:a8:00:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 192.168.0.6/16 brd 192.168.255.255 scope global eth1 valid_lft forever preferred_lft forever [root@4ae93d0df394 /]# exit exit [root@docker ~]# </broadcast,multicast,up,lower_up></broadcast,multicast,up,lower_up></loopback,up,lower_up> |
通过这种方式直接将centos01加到了mynet网络中
总结:
veth pair是成对出现的一种虚拟网络设备接口,一端连着网络协议栈,一端彼此相连。
docker中默认使用docker0网络。
docker0相当于一个路由器的作用,任何一个容器启动默认都是docker0网络。
docker0是容器和虚拟机之间通信的桥梁。
推荐使用自定义网络,更好实现使用服务名的连通方式,避免ip改变的尴尬。
网络之间不能直接连通,网络连通是将一个容器和一个网络之间的连通,实现跨网络操作。
七、dockerfile
7.1、概念
Dockerfile是一个文本文件,文件中包含了一条条指令(instrucation),用于构建镜像。每一条指定构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建。
dockerfile是自定义镜像的一套规则
dockerfie由多条指令构成,Dockerfile中的每一条指令都会对应于Docker镜像中的每一层
dockerfile的原理就是镜像分层
Dockerfile中的每一个指令都会创建一个新的镜像层(是一个临时的容器,执行完成后将不再存在,再往后进行重新的创建于操作)
镜像层将被缓存和复用(后续的镜像曾将基于前面的每一层,每一层都会由下几层的缓存)
当Dockerfile的指令被修改了,复制的文件变化了,或构建镜像时指定的变量不同了,那么对应的镜像层缓存就会失效(因为后续的操作必然更改前面的镜像层)
某一层的镜像缓存失效了之后,它之后的镜像层就会失效(第一层不成功,那么第二层也会失效)
容器的修改并不会影响镜像,如果在某一层中添加一个文件,在下一层中删除它,镜像中依然会包含该文件
7.2、docker镜像的创建
创建镜像有三种方式:
基于已有镜像创建
基于本地模板创建
基于dockerfile创建
7.21、基于现有镜像创建
首先启动一个镜像,在容器中做出修改
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 39 40 41 42 43 44 | #查看所有镜像 [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE tomcat latest 1315d7d3b242 9 days ago 426MB nginx latest 61395b4c586d 3 weeks ago 187MB centos latest 5d0da3dc9764 2 years ago 231MB training/webapp latest 6fae60ef3446 8 years ago 349MB #查看容器 [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES #创建容器 [root@docker ~]# docker create -it centos bash 6572f694b26ebf76de62ee8f00b39e07eacf0b2db3f997e112c266add1bdaff7 #查看 [root@docker ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6572f694b26e centos "bash" 2 seconds ago Created vibrant_bell #将修改后的容器提交为新的镜像,需要使用该容器的 ID 号创建新镜像 commit 常用选项: -m:说明信息 -a:作者信息 -p:生成过程中停止容器的运行 #启动容器 [root@docker ~]# docker start 6572f694b26e 6572f694b26e [root@docker ~]# docker commit -m "new" -a "liy" 6572f694b26e centos:7 sha256:afca1d71b9f0fabaeb0c1da33f8600e237bafef0c328e28c2b6602312b946432 #再次查看镜像 [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos 7 afca1d71b9f0 2 seconds ago 231MB centos latest 04d30e24942b About a minute ago 231MB tomcat latest 1315d7d3b242 9 days ago 426MB nginx latest 61395b4c586d 3 weeks ago 187MB centos 5d0da3dc9764 2 years ago 231MB training/webapp latest 6fae60ef3446 8 years ago 349MB [root@docker ~]# |
7.22、基于本地模板创建
通过导入操作系统模板文件可以生成镜像,模板可以从OPENVZ开源项目下载,下载地址为:
https://wiki.openvz.org/Download/template/precrated
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 | #使用wget命令导入为本地镜像<br>wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz #生成镜像 [root@docker ~]# docker import debian-7.0-x86-minimal.tar.gz -- debian:v1 sha256:d3578c0381cbe67e1a8d52b998395a7f036fdba609db0e99a139b14a142c4c9e 或 [root@docker ~]# cat debian-7.0-x86-minimal.tar.gz |docker import - debian:v2 sha256:3628c3dae8897c4fb6d5ff955286a9d307e2e61a48ed71cf0cece440c94f7307 #查看镜像 [root@docker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE debian v2 3628c3dae889 4 seconds ago 215MB debian v1 7df0fabbef22 25 seconds ago 215MB d3578c0381cb 36 seconds ago 215MB centos 7-1 78d7aca6f874 10 minutes ago 231MB centos 7 afca1d71b9f0 14 minutes ago 231MB centos latest 04d30e24942b 15 minutes ago 231MB tomcat latest 1315d7d3b242 9 days ago 426MB nginx latest 61395b4c586d 3 weeks ago 187MB centos 5d0da3dc9764 2 years ago 231MB training/webapp latest 6fae60ef3446 8 years ago 349MB #创建并启动容器 [root@docker ~]# docker run -itd debian:v1 /bin/bash c0830df3ba2db26f775c2970bc3840e7a4148cee3c580c92acb3148e48d3215f [root@docker ~]# |
7.3、基于dockerfile创建
dockerdile是一组指令组成的文件
dockerfile每行支持一条指令,每条指定可携带多个参数,一条指令可以用&&方式,去写多条指令
dockerfile支持以“#”为开头的注释
7.31、dockerfile结构
基于镜像信息(linux发行版:比如centos、ubuntu、suse、debian、alpine、redhat)
维护者信息(docker search可查看)
镜像操作指令(tar yum make)
容器启动时执行指令(cmd ["/root/run/sh"]、entrypoint、都是系统启动时,第一个加载的程序/脚本/命令)
7.32、dockerfile格式
在编写Dockerfile时,需要遵守严格的格式:
第一行必须使用FROM指令知名所基于的镜像名称
之后使用MAINTAINER指令说明维护该镜像的用户信息
然后是镜像操作相关指令,如RUN指令。每一条指令,都会给基础镜像添加新的一层
最后使用CMD指令指定启动容器时,要运作的命令操作
1 2 3 4 5 6 | FROM centos:latest MAINTAINER huwl RUN yum install gcc -y COPY run.sh /usr/bin EXPOSE 80 CMD ['run.sh] |
7.33、dockerfile构建命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | FROM 指定基础镜像,用于后续的指令构建。 MAINTAINER 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令) LABEL 添加镜像的元数据,使用键值对的形式。 RUN 在构建过程中在镜像中执行命令。 CMD 指定容器创建时的默认命令。(可以被覆盖) ENTRYPOINT 设置容器创建时的主要命令。(不可被覆盖) EXPOSE 声明容器运行时监听的特定网络端口。 ENV 在容器内部设置环境变量。 ADD 将文件、目录或远程URL复制到镜像中。 COPY 将文件或目录复制到镜像中。 VOLUME 为容器创建挂载点或声明卷。 WORKDIR 设置后续指令的工作目录。 USER 指定后续指令的用户上下文。 ARG 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。 ONBUILD 当该镜像被用作另一个构建过程的基础时,添加触发器。 STOPSIGNAL 设置发送给容器以退出的系统调用信号。 HEALTHCHECK 定义周期性检查容器健康状态的命令。 SHELL 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。 |
ENTRYPOINT指令
ENTRYPOINT [“要运行的程序”,“参数1”,“参数2”]
设定容器启动时第一个运行的命令及其参数 可以通过使用命令docker run --entrypoint 来覆盖镜像中的ENTRYPOINT指令的内容。
两种格式:
1 2 3 | exec格式(数值格式):ENTRYPOINT [“命令”,“选项”,“参数”] shell格式:ENTRYPOINT 命令 选项 参数 |
CMD与entrypoint
都是容器启动时要加载的命令
要想了解cmd和entrypoint的区别,首选必须了解exec模式和shell模式的区别
exec模式与shell模式的区别
exec: 容器加载时使用的启动的第一个任务进程
shell: 容器加载时使用的第一个bash(/bin/bash /bin/sh /bin/init)
1 2 3 4 5 | 自检完成后,加载第一个pid = 1 进程 shell 翻译官/解释器,解析 echo $PATH |
exec模式下传入命令
创建的镜像时传入CMD,启动容器时不传入CMD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #创建Dockerfile的工作目录 cd /opt mkdir test #编写Dockerfile文件 vim Dockerfile FROM centos:7 CMD [ "top" ] #基于dockerfile构建镜像 docker build -t centos:7 . #基于构建好的镜像启动容器 -f指定dockerfile文件,不写默认指定当前目录 -t指定镜像名称 . 指定当前目录环境中的文件 docker run -it --name test centos:7 #查看执行的命令 docker logs test #传入ps aux 命令执行,查看结果 docker exec test ps aux |
启动时传入/bin/bash命令
1 2 3 4 5 | #基于构建好的镜像启动容器,并且加上/bin/bash命令 docker run -itd --name test01 centos:7 /bin/bash #通过exec 传入命令查看执行效果 docker exec test01 ps aux |
使用exec模式无法输出环境变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #编写新的dockerfile文件 cd /opt/test vim Dockerfile FROM centos:7 CMD [ "echo" , "$HOME" ] #有shell环境下输出的变量值 echo $HOME #构建dockerfile镜像 docker build -t centos:ydq . #查看镜像 docker images #基于构建好镜像的启动容器 docker run -itd --name ydq centos:ydq #查看运行的容器 docker ps #查看执行结果 docker logs ydq |
shell模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #编写一个dockerfile文件 vim Dockerfile FROM centos:7 CMD [ "sh" , "-c" , "echo $HOME" ] #基于文件编写centos:ydq2的镜像 docker build -t centos:ydq2 #查看镜像 docker images #启动容器 docker run -itd --name ydq3 centos:ydq2 #查看输出日志 docker logs ydq3 |
总结:
CMD和ENTRYPOINT的区别
简单回答
相同点: 都是容器环境启动时需要加载的命令
不同点: CMD不能传参,ENTRYPOINT可以传参
详细回答
不同点
如果ENTRYPOINT是使用shell模式,CMD指令会被忽略
如果ENTRYPOINT是使用exec模式,CMD也会是exec模式,CMD指令的内容作为参数追加到ENTRYPOINT
ADD和copy区别
Dockerfile中的COPY指令和ADD指令都可以将主机上的资源复制或加入到容器镜像中,都是在构建镜像的过程中完成的
copy只能用于复制(节省资源)
ADD复制的同时,如果复制的对象是压缩包,ADD还可以解压(消耗资源)
COPY指令和ADD指令的唯一区别在于是否支持从远程URL获取资源。COPY指令只能从执行docker build所在的主机上读取资源并复制到镜像中。而ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中
满足同等功能的情况下,推荐使用COPY指令。ADD指令更擅长读取本地tar文件并解压缩。
Docker镜像结构的分层
1 2 3 4 5 6 7 | 镜像不是一个单一的文件,而是有多层构成。容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就是删除了其最上面的读写层,文件改动也就丢失了。Docker使用存储驱动管理镜像像每层内容及可读可写的容器层 Dockerfile中的每个指令都会创建一个新的镜像层 镜像层将被缓存和复用 当Dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效。 某一层的镜像缓存失效,它之后的镜像层缓存都会失效 镜像层是不可变的,如果在某一层中添加一个文件,然后在一层中删除它,则镜像中依然会包含该文件,只是这个文件在Docker容器中不可见了 |
docker镜像分层(基于AUFS构建)
docker镜像位于bootfs(内核)之上
每一层镜像的下一层成为父镜像
第一层镜像成为base image(操作系统环境镜像)
容器层(可读可写,为了给用户操作),在最顶层
容器层以下都是readonly
LXC是一种内核中的容器技术,早期docker在没有将资源容器化的功能时,就是靠内核中LXC来完成容器虚拟化的。现在docker 拥有了自己的docker libcontainer库文件,这种库文件可以做到将资源容器化的操作,所以对LXC的依赖性大大降低。
bootfs内核空间
主要包含bootloader(引导程序)和kernel(内核)
bootloader主要引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs
这一层与我们典型的linux/Unix系统时一样的,包含boot加载器和内核,当boot加载完成之后整个内核就都在内存中了,此时内存的使用权有bootfs交给内核,此时系统也会卸载bootfs。
在linux操作系统中,linux加载bootfs时会将rootfs设置为read-only,系统自检后会将只读改为读写,让我们可以在操作系统中进行
rootfs内核空间
bootfs之上(base images,例如centos、ubuntu)
包含的就是典型的linux系统中的/dev,/proc,/bin,/etc等标准目录和文件
rootfs就是各种不同的操作系统发行版
AUFS与overlay/overlay2
AUFS是一种联合文件系统,它使用同一个Linux host上的多个目录,逐个堆叠起来,对外呈现出一个统一的文件系统,AUFS使用该特性,实现了Docker镜像的分层
而docker使用了overlay/overlay2存储驱动来支持分层结构
overlayFS将单个Linux主机上的两个目录合并成一个目录,这些目录被称为层,统一过程被称为联合挂载
overlay结构
overlayfs在Linux主机上只有两层,一个目录在下层,用来保存镜像,另一个目录在上层,用来存储容器信息
1 2 3 4 5 6 7 8 9 10 11 12 | rootfs #基础镜像 lower #下层信息(为镜像层,只读) upper #上层目录(容器信息,可写) worker #运行的工作目录(copy- on -write写时复制-->准备容器环境) mergod #视图层(容器视图) #docker 镜像层次结构总结 1、 base images :基础镜像 2、image :固化了一个标准运行环境,镜像本身的功能-封装一组功能性的文件,通过统一的方式,文件格式提供出来(只读) 3、container :容器层(读写) 4、docker-server 端 5、呈现给docker-client(视图) |
LXC和容器是什么关系?
LXC是内核中容器技术/驱动,功能是将资源容器化。完成资源容器虚拟化的过程。是早期docker的依赖组件目前docker 拥有自己的libcontianer库。可以实现容器虚拟化的功能,对LXC依赖性大大降低。
dockerfile镜像分层的原理
用overlay2存储引擎的方式叠加上去,最上面是容器层是可读可写的,其他镜像是可读的,他们是共用的内核资源,共用的是操作系统里所必须的引导程序,挂载,系统之间的文件,这些文件他和内核之间共享,所以他比实际的centos要小。
容器之间相互通信的方式
docker 0 、 数据卷容器 、 --link 隧道 、 container 模式(直连接口,同一个network namespaces里,通过同一个网卡的方式,在同一个名称空间里 共有一个IP,通过localhost交互/自己的ip或端口交互)
联合文件系统(UnionFS)
UnionFS(联合文件系统) : Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。AUFS、OberlayFS及Devicemapper都是一种UnionFS。
Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:
一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
注:我们下载的时候看到的一层层的就是联合文件系统
镜像加载原理
在Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs.
rootfs在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
我们可以理解成一开始内核里什么都没有,操作一个命令下载debian,这是就会在内核上面加一层基础镜像;再安装一个emacs,会在基础镜像上叠加一层image;接着再安装一个apache,又会在images.上面叠加一层image。最后它们看起来就像一个文件系统即容器的rootfs。在Docker的体系里把这些rootfs叫做Docker的镜像。但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作。当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs.
7.4、Build构建镜像
1 2 3 4 5 6 7 8 9 10 | Usage:docker build [OPTIONS] PATH | URL | - [flags] Options: -t, --tag list # 镜像名称 -f,--file string #指定Dockerfile文件位置 # docker build . # docker bulid -t shykes/myapp . # docker bulid -t shykes/myapp -f /path/Dockerfile /path # docker bulid -t shykes/myapp http://www.example.com/Dockerfile |
7.5、企业应用案例
7.51、构建Nginx基础镜像
Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | [root@docker ~/dockerfile/nginx]# cat Dockerfile FROM centos:7 RUN yum install -y gcc gcc-c++ make \ openssl-devel pcre-devel gd-devel \ iproute net-tools telnet wget curl && \ yum clean all && \ rm -rf / var /cache/yum/* ADD nginx-1.15.5.tar.gz / RUN cd nginx-1.15.5 && \ ./configure --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module && \ make -j 4 && make install && \ mkdir /usr/local/nginx/conf/vhost && \ cd / && rm -rf nginx* && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH:/usr/local/nginx/sbin COPY nginx.conf /usr/local/nginx/conf/nginx.conf WORKDIR /usr/local/nginx EXPOSE 80 CMD [ "nginx" , "-g" , "daemon off;" ] |
构建镜像:
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 | [root@docker ~/dockerfile/nginx]# docker build -t nginx:v1 -f Dockerfile . [+] Building 187.6s (11/11) FINISHED docker: default => [ internal ] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [ internal ] load build definition from Dockerfile 0.0s => => transferring dockerfile: 748B 0.0s => [ internal ] load metadata for docker.io/library/centos:7 11.7s => [1/6] FROM docker.io/library/centos:7@sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b 94.0s => => resolve docker.io/library/centos:7@sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8 0.0s => => sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3b 76.10MB / 76.10MB 88.1s => => sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8d32916d6487418ea4 1.20kB / 1.20kB 0.0s => => sha256:dead07b4d8ed7e29e98de0f4504d87e8880d4347859d839686a31da35a3b532f 529B / 529B 0.0s => => sha256:eeb6ee3f44bd0b5103bb561b4c16bcb82328cfe5809ab675bb17ab3a16c517c9 2.75kB / 2.75kB 0.0s => => extracting sha256:2d473b07cdd5f0912cd6f1a703352c82b512407db6b05b43f2553732b55df3bc 5.4s => [ internal ] load build context 0.0s => => transferring context: 1.03MB 0.0s => [2/6] RUN yum install -y gcc gcc-c++ make openssl-devel pcre-devel gd-devel iproute 67.5s => [3/6] ADD nginx-1.15.5.tar.gz / 0.2s => [4/6] RUN cd nginx-1.15.5 && ./configure --prefix=/usr/local/nginx --with-http_ssl_ 13.2s => [5/6] COPY nginx.conf /usr/local/nginx/conf/nginx.conf 0.0s => [6/6] WORKDIR /usr/local/nginx 0.0s => exporting to image 0.9s => => exporting layers 0.9s => => writing image sha256:fc1a52bf3774f8e51b739036de5dca38c21005cf5c6393a7b4e59c78af124209 0.0s => => naming to docker.io/library/nginx:v1 |
启动测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@docker ~/dockerfile/nginx]# docker run -d --name nginx001 -p 88:80 nginx:v1 67883779bf5f01fea148aeaeff4c07903e7e4323ce0ce7069291c8c42a7867cd [root@docker ~/dockerfile/nginx]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 67883779bf5f nginx:v1 "nginx -g 'daemon of…" 7 seconds ago Up 7 seconds 0.0.0.0:88->80/tcp, :::88->80/tcp nginx001 [root@docker ~/dockerfile/nginx]# curl -I 192.168.100.60:88 HTTP/1.1 200 OK Server: nginx/1.15.5 Date: Thu, 12 Oct 2023 16:24:45 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Thu, 12 Oct 2023 16:17:04 GMT Connection: keep-alive ETag: "65281c00-264" Accept-Ranges: bytes [root@docker ~/dockerfile/nginx]# |
7.52、构建PHP基础镜像
Dockerfile
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 | [root@docker ~/dockerfile/php]# cat Dockerfile FROM centos:7 RUN yum install epel-release -y && \ yum install -y gcc gcc-c++ make gd-devel libxml2-devel \ libcurl-devel libjpeg-devel libpng-devel openssl-devel \ libmcrypt-devel libxslt-devel libtidy-devel autoconf \ iproute net-tools telnet wget curl && \ yum clean all && \ rm -rf / var /cache/yum/* ADD php-5.6.36.tar.gz / RUN cd php-5.6.36 && \ ./configure --prefix=/usr/local/php \ --with-config-file-path=/usr/local/php/etc \ --enable-fpm --enable-opcache \ --with-mysql --with-mysqli --with-pdo-mysql \ --with-openssl --with-zlib --with-curl --with-gd \ --with-jpeg-dir --with-png-dir --with-freetype-dir \ --enable-mbstring --with-mcrypt --enable-hash && \ make -j 4 && make install && \ cp php.ini-production /usr/local/php/etc/php.ini && \ cp sapi/fpm/php-fpm.conf /usr/local/php/etc/php-fpm.conf && \ sed -i "90a \daemonize = no" /usr/local/php/etc/php-fpm.conf && \ mkdir /usr/local/php/log && \ cd / && rm -rf php* && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH:/usr/local/php/sbin COPY php.ini /usr/local/php/etc/ COPY php-fpm.conf /usr/local/php/etc/ WORKDIR /usr/local/php EXPOSE 9000 CMD [ "php-fpm" ] |
构建php镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [root@docker ~/dockerfile/php]# docker build -t php:v1 -f Dockerfile . [+] Building 306.1s (12/12) FINISHED docker: default => [ internal ] load build definition from Dockerfile 0.0s => => transferring dockerfile: 1.29kB 0.0s => [ internal ] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [ internal ] load metadata for docker.io/library/centos:7 2.1s => CACHED [1/7] FROM docker.io/library/centos:7@sha256:be65f488b7764ad3638f236b7b515b3678369a51 0.0s => [ internal ] load build context 0.1s => => transferring context: 19.40MB 0.1s => [2/7] RUN yum install epel-release -y && yum install -y gcc gcc-c++ make gd-devel libx 145.3s => [3/7] ADD php-5.6.36.tar.gz / 7.0s => [4/7] RUN cd php-5.6.36 && ./configure --prefix=/usr/local/php --with-config-file- 150.4s => [5/7] COPY php.ini /usr/local/php/etc/ 0.0s => [6/7] COPY php-fpm.conf /usr/local/php/etc/ 0.0s => [7/7] WORKDIR /usr/local/php 0.0s => exporting to image 1.2s => => exporting layers 1.2s => => writing image sha256:588ae8a44b72c928d800276cfeb2fa5ca829a2cd08008b3ebe0e3ebbcce8b03a 0.0s => => naming to docker.io/library/php:v1 |
启动测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 | [root@docker ~/dockerfile/php]# docker run -d --name php01 php:v1 a121cbc8e1d94bc2d9101a59d5c7d5e44ebc1a67c4675e24162667edb1b39265 [root@docker ~/dockerfile/php]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a121cbc8e1d9 php:v1 "php-fpm" 6 seconds ago Up 5 seconds 9000/tcp php01 [root@docker ~/dockerfile/php]# docker exec -it php01 bash [root@a121cbc8e1d9 php]# sbin/php-fpm -v PHP 5.6.36 (fpm-fcgi) (built: Oct 12 2023 16:37:01) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies [root@a121cbc8e1d9 php]# |
7.53、构建Tomcat基础镜像并项目测试
Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | [root@docker ~/dockerfile/tomcat]# cat Dockerfile FROM centos:7 ENV VERSION=8.5.43 RUN yum install java-1.8.0-openjdk wget curl unzip iproute net-tools -y && \ yum clean all && \ rm -rf / var /cache/yum/* ADD apache-tomcat-${VERSION}.tar.gz /usr/local/ RUN mv /usr/local/apache-tomcat-${VERSION} /usr/local/tomcat && \ sed -i '1a JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"' /usr/local/tomcat/bin/catalina.sh && \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime ENV PATH $PATH:/usr/local/tomcat/bin WORKDIR /usr/local/tomcat EXPOSE 8080 CMD [ "catalina.sh" , "run" ] |
构建镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [root@docker ~/dockerfile/tomcat]# docker build -t tomcat:v1 -f Dockerfile . [+] Building 67.6s (10/10) FINISHED docker: default => [ internal ] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [ internal ] load build definition from Dockerfile 0.0s => => transferring dockerfile: 614B 0.0s => [ internal ] load metadata for docker.io/library/centos:7 1.7s => CACHED [1/5] FROM docker.io/library/centos:7@sha256:be65f488b7764ad3638f236b7b515b3678369a51 0.0s => [ internal ] load build context 0.1s => => transferring context: 9.72MB 0.1s => [2/5] RUN yum install java-1.8.0-openjdk wget curl unzip iproute net-tools -y && yum cl 63.8s => [3/5] ADD apache-tomcat-8.5.43.tar.gz /usr/local/ 0.4s => [4/5] RUN mv /usr/local/apache-tomcat-8.5.43 /usr/local/tomcat && sed -i '1a JAVA_OPTS=" 0.7s => [5/5] WORKDIR /usr/local/tomcat 0.0s => exporting to image 0.9s => => exporting layers 0.9s => => writing image sha256:6eeef315375ba20a5f71c1919797f0536fe0334f5f5464d76c1a1c260d97c7fe 0.0s => => naming to docker.io/library/tomcat:v1 0.0s |
启动测试:
1 2 3 4 5 6 7 | [root@docker ~/dockerfile/tomcat]# docker run -d --name tomcat01 -p 8080:8080 tomcat:v1 483d9bf0b20d7ee8022854a9ed34fa1f8d1a6909fc17982d8dd2161b15e0763f [root@docker ~/dockerfile/tomcat]# curl -I http: //192.168.100.60:8080 HTTP/1.1 200 Content-Type: text/html;charset=UTF-8 Transfer-Encoding: chunked Date: Thu, 12 Oct 2023 16:57:14 GMT |
7.6、快速部署LNMP网站平台
创建自定义网络
1 | docker network create lnmp |
创建MySQL容器
1 | docker run -d --name lnmp_mysql --net lnmp --mount src=mysql-vol,dst=/ var /lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress mysql:5.7 --character- set -server=utf8 |
创建PHP容器
1 | docker run -d --name lnmp_php --net lnmp --mount src=wwwroot,dst=/wwwwroot php:v1 |
创建NGINX容器
1 2 | [root@docker ~/dockerfile/nginx]# docker run -d --name lnmp_nginx --net lnmp -p 80:80 --mount type=bind,src=$(pwd)/nginx.conf,dst=/usr/local/nginx/conf/nginx.conf --mount src=wwwroot,dst=/wwwroot nginx:v1 24cbc22a091de1fd7a596fd2989a621be877a340875476a5a8ac25908800e203 |
参考博客链接:
https://blog.csdn.net/qq_69278945/article/details/127461465
https://www.cnblogs.com/0x00000/p/9158982.html#%E4%B8%83dockerfile
https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247548982&idx=2&sn=5be5068c6e55ab4826c1a757541fcba2&chksm=fbb189c8ccc600dea4b502d9d5bcc0c779b69d93c69d382db26a27768c772736cead35eed3f8&scene=27
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY