Docker 底子实战:环境搭建、容器、堆栈、镜像

火影  金牌会员 | 2024-9-30 16:35:35 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 742|帖子 742|积分 2226


Docker 底子实战

   可以使用 docker help 大概 man docker-run 来获取完备的 Docker 下令列表,本文只介绍一些常用的下令与参数。
  环境搭建

考虑到安装流程过于繁琐,在 CentOS 中,可以使用官方提供的脚原来快速安装 Docker:
   可以从 https://get.docker.com/ 检察支持的操作系统。
  1. # 获取安装脚本
  2. curl -fsSL get.docker.com -o get-docker.sh
  3. # 执行安装,并使用aliyun的源加速
  4. sudo sh get-docker.sh --mirror Aliyun
复制代码
当安装完毕后,设置开机自启动 Docker:
  1. # 设置开机自启
  2. sudo systemctl enable docker
  3. # 启动docker
  4. sudo systemctl start docker
复制代码
由于 Docker 下令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket,因此我们需要将当前用户加入 docker 用户组中:
  1. # 建立docker用户组
  2. sudo groupadd docker
  3. # 将当前用户加入docker组:
  4. sudo usermod -aG docker $USER
复制代码
重启终端后,随便输入一个下令测试是否设置乐成,比方:
  1. docker run --rm hello-world
复制代码
为了提供镜像的拉取速度,这里还需要设置国内的镜像,这里给几个常用的镜像源:


  • 阿里云:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors,登录上面这个页面后在镜像工具->镜像加快器页面检察个人专属镜像源。
  • 网易云:https://hub-mirror.c.163.com
  • 百度云:https://mirror.baidubce.com
接着执行下面的下令,修改 daemon 设置文件,将镜像源添加进去:
  1. # 创建配置文件夹
  2. sudo mkdir -p /etc/docker
  3. # 写入镜像信息
  4. sudo tee /etc/docker/daemon.json <<-'EOF'
  5. {
  6.   "registry-mirrors": [
  7.     "https://92ycev6l.mirror.aliyuncs.com",
  8.     "https://hub-mirror.c.163.com",
  9.     "https://mirror.baidubce.com"
  10.   ]
  11. }
  12. EOF
  13. # daemon进程加载配置文件
  14. sudo systemctl daemon-reload
  15. # 重启docker服务
  16. sudo systemctl restart docker
复制代码
重启服务,即可完成设置:
  1. sudo systemctl daemon-reload
  2. sudo systemctl restart docker
复制代码


容器

启动容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,别的一个是将在停止状态(exited)的容器重新启动。
新建并启动容器

这里我们以 docker 自带的镜像 ubuntu 来进行演示,运行 docker run 下令创建容器,比方:
  1. docker run --name ubuntu -it ubuntu /bin/bash
复制代码
这里表明一下这个下令用到的参数和选项,首先 –name 用于指定容器的名字(如果不指定则会随机天生一个容器 id),我们在后续的操作中可以直接使用这个名字来操作容器。接着 -t参数用于为该容器分配一个伪终端(pseudo-tty),这样该容器才气具备一个交互式的 shell。-i 参数保证容器的标准输入(stdin)保持打开,这样我们就可以通过终端在该容器中执行下令。接着的 ubuntu 其实就是指定创建容器所需要的镜像,而最后的 /bin/bash/ 则是在容器中启动了一个 bash shell。
   当我们运行这个下令之后,docker 它会做一些什么样的操作呢?
  

  • docker 会检查本地是否存在对应的镜像,如果不存在则会去 docker hub registry 中查找,并生存到本地。
  • docker 使用该镜像创建并启动一个容器。
  • docker 开始构建容器环境,包括以下内容:

    • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层。
    • 从宿主主机设置的网桥接口中桥接一个假造接口到容器中
    • 从地址池为容器设置一个 ip 地址。

  • docker 开始执行用户在 bash shell 中输入的下令。
  • 当用户退出 bash 后停止容器。


停止容器

在容器启动后,我们可以随时使用 docker stop 下令来停止容器,比方:
  1. docker stop [id/name]
复制代码
也可以直接在容器中使用 exit 下令,大概直接关闭 bash 来停止容器。


启动已停止容器

当容器停止后,我们可以使用 docker start 下令来将其启动,比方:
  1. docker start [id/name]
复制代码
我们还也可以使用 docker restart 下令来重启一个容器。
   在某些场景中,我们也可以使用 docker create 和 docker start 来更细粒度的控制容器。
  

创建守护态容器

有的时候我们想要创建一些长期运行的容器,比方一些服务、应用步伐等,这时就可以在创建容器时加上 -d 选项,将容器设置为守护态容器(daemonized container),比方:
  1. docker run --name daemon_mysql -d mysql /bin/bash
复制代码
此时 docker 会将容器放到背景运行(即 daemon 历程),而且不会将主机的控制台附着到新的 shell 会话上,其只会返回一个容器 id。
   需要留意的是, 容器是否会长久运行,是和 docker run 指定的下令有关,和 -d 参数无关。 纵然加上了 -d,还必须确保容器存在一个前台历程,否则仍旧无法背景运行。
  此时我们没有办法通过终端来看到容器的输出,需要通过容器日志来获取到其标准输出(stdout)。


容器日志

检察日志

我们可以使用 docker logs 下令来检察容器的日志(即标准输出),比方:
  1. docker logs [id/name]
复制代码
通常我们还会配合 -t 与 -f 选项一起使用。-t 的作用是为每条日志加上时间戳,而 -f 则是及时返回容器日志。


日志驱动

在 docker 1.6 之后,我们可以控制 docker 容器所用的日志驱动,可以在创建容器时通过 --log-driver 选项来实现,比方:
  1. docker run --log-driver="syslog" --name daemon_dwayne -d
  2. ubuntu /bin/sh -c "while true; do echo hello world; sleep 1;
  3. done"
复制代码
常用的选项有以下几种:


  • json-file:默认选项,提供了 docker logs 下令。
  • syslog:禁用 docker logs,而且将所有容器的日志输出都重定向到 Syslog。
  • none:会禁用所有容器中的日志,从而导致 docker logs 也被禁用。


进入容器

某些时候我们可能想要进入容器的内部执行一些操作(守护态容器、重启后的交互式容器),这时候就可以使用 docker attach 或 docker exec。
docker attach

我们可以使用 docker attach 下令来附着到一个容器的 shell 上,比方:
  1. docker attach [id/name]
复制代码
此时我们就可以在容器的 bash 上执行我们想要进行的操作。
   需要留意的是 docker attach 在退出 bash 时,会导致该容器的停止。
  

docker exec

docker exec 下令可以在容器内部额外启动新历程(包括 shell),用法如下:
  1. docker exec -it ubuntu /bin/bash
复制代码
这里的选项的含义与 docker run 相同,这里就不外多介绍了。
   docker exec 退出 bash 时并不会导致容器的停止,以是我们通常用它来进入容器。
  

容器信息

docker ps


docker ps
可以用来检察当前存在的容器列表,以及它们的一些根本信息:
  1. docker ps
复制代码
  默认查找出运行中的容器,如果想检察全部容器需要加上 -a 参数
  此时就会显示出这些容器的 id、镜像、启动时使用的下令、创建时间、状态、端口、容器名称,比方:
  1. CONTAINER ID   IMAGE               COMMAND                  CREATED        STATUS        PORTS                                                  NAMES
  2. 3c80a71e0927   keking/kkfileview   "java -Dfile.encodin…"   4 months ago   Up 3 months   0.0.0.0:8012->8012/tcp, :::8012->8012/tcp              agitated_lalande
  3. d86da50629af   mysql:5.7           "docker-entrypoint.s…"   4 months ago   Up 3 months   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql
复制代码


docker inspect

如果你觉得 docker ps
所展示的信息还不敷详细,可以使用 docker inspect 来获得更多的容器信息。
  1. docker inspect [id/name]
复制代码
docker inspect 下令会对容器进行详细的检查,然后返回其设置信息,包括名称、下令、网络设置以及很多有用的数据。比方:
  1. [
  2.     {
  3.         "Id": "3c80a71e09279d83a92e3c4674b6d8f6175fee57402546496058af6f0ec69aa6",
  4.         "Created": "2022-03-17T14:26:27.842511963Z",
  5.         "Path": "java",
  6.         "Args": [
  7.             "-Dfile.encoding=UTF-8",
  8.             "-Dspring.config.location=/opt/kkFileView-4.1.0-SNAPSHOT/config/application.properties",
  9.             "-jar",
  10.             "/opt/kkFileView-4.1.0-SNAPSHOT/bin/kkFileView-4.1.0-SNAPSHOT.jar",
  11.             "--name",
  12.             "kkfileview"
  13.         ],
  14.         "State": {
  15.             "Status": "running",
  16.             "Running": true,
  17.             "Paused": false,
  18.             "Restarting": false,
  19.             "OOMKilled": false,
  20.             "Dead": false,
  21.             "Pid": 6440,
  22.             "ExitCode": 0,
  23.             "Error": "",
  24.             "StartedAt": "2022-04-12T03:21:40.84672668Z",
  25.             "FinishedAt": "2022-04-12T11:20:06.846679652+08:00"
  26.         },
  27.         "Image": "sha256:17aa16bf244f7d5c4886b7322820a83fd401fda5e5fc153bd9a30d2c56075ac5",
  28.         "ResolvConfPath": "/var/lib/docker/containers/3c80a71e09279d83a92e3c4674b6d8f6175fee57402546496058af6f0ec69aa6/resolv.conf",
  29.         "HostnamePath": "/var/lib/docker/containers/3c80a71e09279d83a92e3c4674b6d8f6175fee57402546496058af6f0ec69aa6/hostname",
  30.         "HostsPath": "/var/lib/docker/containers/3c80a71e09279d83a92e3c4674b6d8f6175fee57402546496058af6f0ec69aa6/hosts",
  31.         "LogPath": "/var/lib/docker/containers/3c80a71e09279d83a92e3c4674b6d8f6175fee57402546496058af6f0ec69aa6/3c80a71e09279d83a92e3c4674b6d8f6175fee57402546496058af6f0ec69aa6-json.log",
  32.         "Name": "/agitated_lalande",
  33.         "RestartCount": 0,
  34.         "Driver": "overlay2",
  35.         "Platform": "linux",
  36.         "MountLabel": "",
  37.         "ProcessLabel": "",
  38.         "AppArmorProfile": "",
  39.         "ExecIDs": null,
  40.         "HostConfig": {
  41.             "Binds": null,
  42.             "ContainerIDFile": "",
  43.             "LogConfig": {
  44.                 "Type": "json-file",
  45.                 "Config": {}
  46.             },
  47.             "NetworkMode": "default",
  48.             "PortBindings": {
  49.                 "8012/tcp": [
  50.                     {
  51.                         "HostIp": "",
  52.                         "HostPort": "8012"
  53.                     }
  54.                 ]
  55.             },
  56.             "RestartPolicy": {
  57.                 "Name": "no",
  58.                 "MaximumRetryCount": 0
  59.             },
  60.             "AutoRemove": false,
  61.             "VolumeDriver": "",
  62.             "VolumesFrom": null,
  63.             "CapAdd": null,
  64.             "CapDrop": null,
  65.             "CgroupnsMode": "host",
  66.             "Dns": [],
  67.             "DnsOptions": [],
  68.             "DnsSearch": [],
  69.             "ExtraHosts": null,
  70.             "GroupAdd": null,
  71.             "IpcMode": "private",
  72.             "Cgroup": "",
  73.             "Links": null,
  74.             "OomScoreAdj": 0,
  75.             "PidMode": "",
  76.             "Privileged": false,
  77.             "PublishAllPorts": false,
  78.             "ReadonlyRootfs": false,
  79.             "SecurityOpt": null,
  80.             "UTSMode": "",
  81.             "UsernsMode": "",
  82.             "ShmSize": 67108864,
  83.             "Runtime": "runc",
  84.             "ConsoleSize": [
  85.                 0,
  86.                 0
  87.             ],
  88.             "Isolation": "",
  89.             "CpuShares": 0,
  90.             "Memory": 0,
  91.             "NanoCpus": 0,
  92.             "CgroupParent": "",
  93.             "BlkioWeight": 0,
  94.             "BlkioWeightDevice": [],
  95.             "BlkioDeviceReadBps": null,
  96.             "BlkioDeviceWriteBps": null,
  97.             "BlkioDeviceReadIOps": null,
  98.             "BlkioDeviceWriteIOps": null,
  99.             "CpuPeriod": 0,
  100.             "CpuQuota": 0,
  101.             "CpuRealtimePeriod": 0,
  102.             "CpuRealtimeRuntime": 0,
  103.             "CpusetCpus": "",
  104.             "CpusetMems": "",
  105.             "Devices": [],
  106.             "DeviceCgroupRules": null,
  107.             "DeviceRequests": null,
  108.             "KernelMemory": 0,
  109.             "KernelMemoryTCP": 0,
  110.             "MemoryReservation": 0,
  111.             "MemorySwap": 0,
  112.             "MemorySwappiness": null,
  113.             "OomKillDisable": false,
  114.             "PidsLimit": null,
  115.             "Ulimits": null,
  116.             "CpuCount": 0,
  117.             "CpuPercent": 0,
  118.             "IOMaximumIOps": 0,
  119.             "IOMaximumBandwidth": 0,
  120.             "MaskedPaths": [
  121.                 "/proc/asound",
  122.                 "/proc/acpi",
  123.                 "/proc/kcore",
  124.                 "/proc/keys",
  125.                 "/proc/latency_stats",
  126.                 "/proc/timer_list",
  127.                 "/proc/timer_stats",
  128.                 "/proc/sched_debug",
  129.                 "/proc/scsi",
  130.                 "/sys/firmware"
  131.             ],
  132.             "ReadonlyPaths": [
  133.                 "/proc/bus",
  134.                 "/proc/fs",
  135.                 "/proc/irq",
  136.                 "/proc/sys",
  137.                 "/proc/sysrq-trigger"
  138.             ]
  139.         },
  140.         "GraphDriver": {
  141.             "Data": {
  142.                 "LowerDir": "/var/lib/docker/overlay2/e5617afc1d414b95b27bd0993ef4b4f56bb7c4d863fbdfe0fd9637cf45a446e4-init/diff:/var/lib/docker/overlay2/422ff17c3c84c125a5b5f5187670f5c2d0d3b8fb8b9a3323cd8c35c5dc06c5d5/diff:/var/lib/docker/overlay2/496143afbc6136bd48f26c6e247f5ecd38d138f8ef0068ccb810a7c12817c931/diff:/var/lib/docker/overlay2/afd959b170baface760ce9c0521dff4d5a9326fb518189bf958a4e51ecc5d51a/diff:/var/lib/docker/overlay2/7e5d0edc4323531ed7a79f10ba3aea8b9c8788db150b2359dbf478b536271edb/diff",
  143.                 "MergedDir": "/var/lib/docker/overlay2/e5617afc1d414b95b27bd0993ef4b4f56bb7c4d863fbdfe0fd9637cf45a446e4/merged",
  144.                 "UpperDir": "/var/lib/docker/overlay2/e5617afc1d414b95b27bd0993ef4b4f56bb7c4d863fbdfe0fd9637cf45a446e4/diff",
  145.                 "WorkDir": "/var/lib/docker/overlay2/e5617afc1d414b95b27bd0993ef4b4f56bb7c4d863fbdfe0fd9637cf45a446e4/work"
  146.             },
  147.             "Name": "overlay2"
  148.         },
  149.         "Mounts": [],
  150.         "Config": {
  151.             "Hostname": "3c80a71e0927",
  152.             "Domainname": "",
  153.             "User": "",
  154.             "AttachStdin": false,
  155.             "AttachStdout": false,
  156.             "AttachStderr": false,
  157.             "ExposedPorts": {
  158.                 "8012/tcp": {}
  159.             },
  160.             "Tty": true,
  161.             "OpenStdin": true,
  162.             "StdinOnce": false,
  163.             "Env": [
  164.                 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/jdk1.8.0_251/bin",
  165.                 "JAVA_HOME=/usr/local/jdk1.8.0_251",
  166.                 "CLASSPATH=/usr/local/jdk1.8.0_251/lib/dt.jar:/usr/local/jdk1.8.0_251/lib/tools.jar",
  167.                 "LANG=zh_CN.UTF-8",
  168.                 "LC_ALL=zh_CN.UTF-8",
  169.                 "KKFILEVIEW_BIN_FOLDER=/opt/kkFileView-4.1.0-SNAPSHOT/bin"
  170.             ],
  171.             "Cmd": [
  172.                 "--name",
  173.                 "kkfileview"
  174.             ],
  175.             "Image": "keking/kkfileview",
  176.             "Volumes": null,
  177.             "WorkingDir": "",
  178.             "Entrypoint": [
  179.                 "java",
  180.                 "-Dfile.encoding=UTF-8",
  181.                 "-Dspring.config.location=/opt/kkFileView-4.1.0-SNAPSHOT/config/application.properties",
  182.                 "-jar",
  183.                 "/opt/kkFileView-4.1.0-SNAPSHOT/bin/kkFileView-4.1.0-SNAPSHOT.jar"
  184.             ],
  185.             "OnBuild": null,
  186.             "Labels": {}
  187.         },
  188.         "NetworkSettings": {
  189.             "Bridge": "",
  190.             "SandboxID": "c79b97931e4c90e792a69908532bec655707d8b2177902b3123f48843ad97b64",
  191.             "HairpinMode": false,
  192.             "LinkLocalIPv6Address": "",
  193.             "LinkLocalIPv6PrefixLen": 0,
  194.             "Ports": {
  195.                 "8012/tcp": [
  196.                     {
  197.                         "HostIp": "0.0.0.0",
  198.                         "HostPort": "8012"
  199.                     },
  200.                     {
  201.                         "HostIp": "::",
  202.                         "HostPort": "8012"
  203.                     }
  204.                 ]
  205.             },
  206.             "SandboxKey": "/var/run/docker/netns/c79b97931e4c",
  207.             "SecondaryIPAddresses": null,
  208.             "SecondaryIPv6Addresses": null,
  209.             "EndpointID": "ea365ddad7c6fd126eab3885a92331ed432bd1e9495f06e65267016c470e07a4",
  210.             "Gateway": "172.17.0.1",
  211.             "GlobalIPv6Address": "",
  212.             "GlobalIPv6PrefixLen": 0,
  213.             "IPAddress": "172.17.0.3",
  214.             "IPPrefixLen": 16,
  215.             "IPv6Gateway": "",
  216.             "MacAddress": "02:42:ac:11:00:03",
  217.             "Networks": {
  218.                 "bridge": {
  219.                     "IPAMConfig": null,
  220.                     "Links": null,
  221.                     "Aliases": null,
  222.                     "NetworkID": "d85e9121a8111af4ff74c675c38f082932c30ba411f8c3fbc20357437970693d",
  223.                     "EndpointID": "ea365ddad7c6fd126eab3885a92331ed432bd1e9495f06e65267016c470e07a4",
  224.                     "Gateway": "172.17.0.1",
  225.                     "IPAddress": "172.17.0.3",
  226.                     "IPPrefixLen": 16,
  227.                     "IPv6Gateway": "",
  228.                     "GlobalIPv6Address": "",
  229.                     "GlobalIPv6PrefixLen": 0,
  230.                     "MacAddress": "02:42:ac:11:00:03",
  231.                     "DriverOpts": null
  232.                 }
  233.             }
  234.         }
  235.     }
  236. ]
复制代码


docker top

docker top 下令用来检察容器内部运行的历程,比方:
  1. docker top [id/name]
复制代码
此时我们就能够看到容器内的所有历程、运行历程的用户及历程 ID,比方:
  1. UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
  2. root                6440                6421                0                   Apr12               ?                   01:45:19            java -Dfile.encoding=UTF-8 -Dspring.config.location=/opt/kkFileView-4.1.0-SNAPSHOT/config/application.properties -jar /opt/kkFileView-4.1.0-SNAPSHOT/bin/kkFileView-4.1.0-SNAPSHOT.jar --name kkfileview
  3. root                6520                6440                0                   Apr12               ?                   00:00:00            /opt/libreoffice7.1/program/soffice.bin -accept=socket,host=127.0.0.1,port=2001;urp; -env:UserInstallation=file:///tmp/.jodconverter_socket_host-127.0.0.1_port-2001 -headless -nocrashreport -nodefault -nofirststartwizard -nolockcheck -nologo -norestore
  4. root                6541                6440                0                   Apr12               ?                   00:00:00            /opt/libreoffice7.1/program/soffice.bin -accept=socket,host=127.0.0.1,port=2002;urp; -env:UserInstallation=file:///tmp/.jodconverter_socket_host-127.0.0.1_port-2002 -headless -nocrashreport -nodefault -nofirststartwizard -nolockcheck -nologo -norestore
复制代码


docker stats

docker stats 下令用来显示一个或多个容器的统计信息,使用方法如下:
  1. docker stats [id1/name1] [id2/name2] [...]
复制代码
我们能看到这些容器的 CPU、内存、网络 I/O 及存储 I/O 的性能和指标,可以用于快速的监控各个容器的负载情况。
  1. CONTAINER ID   NAME               CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O       PIDS
  2. 3c80a71e0927   agitated_lalande   0.07%     420.6MiB / 3.649GiB   11.26%    2.27MB / 50.9MB   510MB / 401kB   44
  3. d86da50629af   mysql              0.03%     307.3MiB / 3.649GiB   8.22%     172MB / 518MB     117MB / 604MB   36
复制代码


删除容器

当我们已经不再想要使用这些容器时,可以使用 docker rm 来删除容器:
  1. docker rm [id/name]
复制代码
  如果想要删除运行中的容器,可以加上 -f 选项逼迫删除。
  如果我们想要批量删除所有停止状态下的容器,可以使用下面这个下令:
  1. docker container prune
复制代码
而如果想一次性删除全部的容器,该怎么做呢?这时候可以先使用 docker ps
获取到所有容器 id,再传给 docker rm 进行批量删除:
  1. docker rm `docker ps
  2. -a -q`
复制代码


容器快照

某些时候,如果我们想要备份当前的容器,又大概是盼望将其同步到多台呆板上,此时就可以通过导出、导入容器的快照来实现。
   快照与镜像文件有什么区别呢?快照文件将抛弃所有的历史记载和元数据信息(即仅生存容器当时的快照状态),而镜像存储文件将生存完备记载,体积也更大。
  导出快照

我们可以使用 docker export 下令来导出本地的容器,比方:
  1. docker export [id/name] > [文件名.tar]
复制代码
此时我们就可以获得导出的快照文件。


导入快照

对于导出的快照,我们可以使用 docker import 将其导入为镜像,比方:
  1. docker import [快照路径] [镜像名]
复制代码


堆栈

Docker Hub

目前 Docker 官方维护了一个公共堆栈 Docker Hub,其中已经包括了数量凌驾 2,650,000 的镜像。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
为了区分同一个堆栈中的不同镜像,Docker 提供了一种称为标签(tag)的功能。每个镜像在列出来时都带有一个标签,如12.04 、12.10 、quantal 大概 precise 等。每个标签对构成特定镜像的一些镜像层进行标志。这种机制使得在同一个堆栈中可以存储多个镜像。
Docker Hub 中有两种类型的堆栈:


  • 用户堆栈(user repository):用户堆栈的镜像都是由 Docker 用户创建的,因此用户堆栈的定名由用户名和堆栈名两部分构成,比方 jamtur01/puppet。
  • 顶层堆栈(top-level repository):顶层堆栈由 Docker 公司和由选定的能提供优质底子镜像的厂商管理,因此顶层堆栈只包含堆栈名部分。
我们可以在 https://hub.docker.com 注册一个 docker 账号,接着在下令行使用 docker login 登录账号,就可以访问远程堆栈中的镜像了。当想要退出账号时,可以使用 docker logout 下令。


本地堆栈

如果我们需要构建和存储包含不想被公开的信息或数据的镜像,这时候我们有以下两种选择:

  • 使用 Docker Hub 上的私有堆栈。
  • 本身搭建私有的镜像堆栈。
这里就介绍一下如何使用 docker-registry 来构建一个构建私有的镜像堆栈。
构建 registry 容器

我们可以直接使用官方提供的 registry 镜像来启动私有堆栈:
  1. docker run -d \
  2.     -p 5000:5000 \
  3.     -v /opt/data/registry:/var/lib/registry \
  4.     --restart=always
  5.     --name registry
  6.     registry
复制代码
这里的 -v 参数用于指定镜像文件的存储路径,–restart 则是为容器设置自动重启。之后我们就可以直接向 127.0.0.1:5000 推送我们的镜像。


设置非 https 堆栈地址

如果我们是在内网环境进行开辟协作,我们就需要用一个内网地址作为私有堆栈的地址,而且取消 docker 对非 https 的限制(docker 默认拒绝以非 HTTPS 的方式推送镜像)。我们需要在 /etc/docker/daemon.json 文件中写入以下内容:
  1. {
  2.   "insecure-registries": [
  3.     "192.168.199.100:5000"
  4.   ]
  5. }
复制代码


镜像

文件系统层

   在讲解镜像操作之前,我们先来思考一个问题,为什么我们能够基于一个镜像来构建另一个镜像?它究竟是由什么构成的?
  Docker 的镜像其实就是一个层层叠加的文件系统构成的,如下图所示:

   Docker 文件系统层  在最底下是一个引导文件系统(bootfs),其包含了 bootloader 和 linux 内核两部分,用户无法对这一层进行修改。当容器启动后,该层就会被卸载,以留出更多的内存供 initrd 磁盘镜像使用。
在引导文件系统之上的是 root 文件系统 rootfs,它可以是一种大概多种操作系统(比方 CentOS 大概 Ubuntu)。
   那 Docker 是如何将这些文件系统团结在一起的呢?
  Docker 使用了一种叫做团结加载(union mount)的技术,在 root 文件系统层上加载更多的只读文件系统。团结加载指的是一次同时加载多个文件系统,但是在外面看起来只能看到一个文件系统。团结加载会将各层文件系统叠加到一起,这样终极的文件系统会包含所有底层的文件和目次。
接着就到了一层一层堆叠的镜像。一个镜像可以放到另一个镜像的顶部,位于下面的镜像称为父镜像(parent image),可以依次类推,直到镜像栈的最底部,最底部的镜像称为底子镜像(base image)。
最后,当从一个镜像启动容器时,Docker 会在该镜像的最顶层加载一个读写文件系统。我们想在 Docker 中运行的步伐就是在这个读写层中执行的。
当 Docker 第一次启动一个容器时,初始的读写层是空的。当文件系统发生变化时,这些变化都会应用到这一层上。好比,如果想修改一个文件,这个文件首先会从该读写层下面的只读层复制到该读写层。该文件的只读版本依然存在,但是已经被读写层中的该文件副本所隐藏,这也就是我们通常提到的写时拷贝机制。


列出镜像

我们可以使用 docker images
下令来列出本地已经下载的镜像:
  1. docker images
复制代码
列表中包含了堆栈名、标签、镜像 ID、创建时间以及所占用的空间,比方:
  1. REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
  2. codercom/code-server   latest    dc6f07d1c0f8   6 months ago    1.63GB
  3. mysql                  latest    3218b38490ce   7 months ago    516MB
  4. keking/kkfileview      latest    17aa16bf244f   7 months ago    1.58GB
  5. hello-world            latest    feb5d9fea6a5   10 months ago   13.3kB
复制代码


查找镜像

我们可以通过 docker search 下令来查找所有 Docker Hub 上公共的可用镜像:
  1. docker search [镜像名]
复制代码
比方我们查找 redis 镜像,此时就能够获取到相关镜像的堆栈名、镜像形貌、关注数、是否官方、是否自动构建等信息,如下:
  1. NAME                                               DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
  2. redis                                              Redis is an open source key-value store that…   11160     [OK]
  3. bitnami/redis                                      Bitnami Redis Docker Image                      227                  [OK]
  4. bitnami/redis-sentinel                             Bitnami Docker Image for Redis Sentinel         39                   [OK]
  5. bitnami/redis-cluster                                                                              34
  6. rapidfort/redis-cluster                            RapidFort optimized, hardened image for Redi…   15
  7. rapidfort/redis                                    RapidFort optimized, hardened image for Redi…   15
  8. circleci/redis                                     CircleCI images for Redis                       14                   [OK]
  9. ubuntu/redis                                       Redis, an open source key-value store. Long-…   10
  10. bitnami/redis-exporter                                                                             9
  11. google/guestbook-python-redis                      A simple guestbook example written in Python…   5
  12. clearlinux/redis                                   Redis key-value data structure server with t…   4
  13. ibmcom/redis-ha                                                                                    1
  14. ibmcom/ibm-cloud-databases-redis-catalog           Catalog image for the IBM Operator for Redis    1
  15. bitnami/redis-sentinel-exporter                                                                    1
  16. ibmcom/ibm-cloud-databases-redis-operator          Container image for the IBM Operator for Red…   1
  17. ibmcom/ibm-cloud-databases-redis-operator-bundle   Bundle image for the IBM Operator for Redis     1
  18. rancher/redislabs-ssl                                                                              0
  19. rapidfort/redis6-ib                                RapidFort optimized, hardened image for Redi…   0
  20. drud/redis                                         redis                                           0                    [OK]
  21. blackflysolutions/redis                            Redis container for Drupal and CiviCRM          0
  22. ibmcom/redisearch-ppc64le                                                                          0
  23. greenbone/redis-server                             A redis service container image for the Gree…   0
  24. vmware/redis-photon                                                                                0
  25. cimg/redis                                                                                         0
  26. ibmcom/redis-ppc64le                                                                               0
复制代码


拉取镜像

当我们用 docker run 下令拉取镜像时,如果本地没有,则会自动从 Docker Hub 下载。除了这种方式,我们也可以本身主动使用 docker pull 拉取镜像:
  1. docker pull [Docker Registry 地址[:端口号]/]仓库名[:标签]
复制代码
在拉取完成后,docker 还会给出该镜像完备的 sha256 的择要,以确保下载同等性。


构建镜像

docker commit

为了方便演示,这里我们就创建一个 CentoS 8 的 nginx 镜像为例子:
  1. # 首先,创建并运行一个centos8镜像
  2. docker run -it centos /bin/bash
  3. # 接着,配置yum仓库源(centos官方已结束对该版本的支持,因此需要重新配置yum仓库源)
  4. sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
  5. sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
  6. # 最后,使用yum安装nginx
  7. yum install -y nginx
  8. # 验证是否安装成功
  9. nginx -v
  10. # 退出容器
  11. exit
复制代码
这里,我们基于一个 CentOS 8 的镜像创建了一个容器,并在该容器中安装了一个 nginx,为了能够将这个容器的当前状态生存下来,以后不必每次都执行这样的操作,我们需要将其制作成为一个镜像。
制作容器最简单的方法是使用 docker commit 下令,比方:
  1. docker commit -m "centos-nginx" 43c02f31293c orekilee/nginx:webserver
复制代码
在这条下令中,我们首先使用 -m 指定了镜像的提交信息,接着指定了容器的 id,最后指定了镜像的用户名以及堆栈名,并为该镜像打上了一个 webserver 的 tag。这样我们就完成了一个简单的镜像的制作,之后我们可以使用 orekilee/nginx:webserver 直接访问到该镜像。
从上面 docker commit 的流程我们可以看出一个问题,这个镜像的制作过程是完全黑箱的,除了制作的人知道它执行过什么下令、如何进行构建,其他人根本无从得知,这就带来了以下几个问题:

  • 可能存在大量无关的内容,导致镜像极为痴肥,而且每一次在该镜像上构建新的镜像时,这些内容都会保存下来,越来越痴肥。
  • 镜像整个制作过程完全黑箱,存在安全隐患。
  • 无法知道构建流程和执行下令,后续维护成本较高。
基于以上问题,我们通常会使用 Dockerfile 文件和 docker build 下令来构建镜像。


Dockerfile

Dockerfile 是一个文本文件,其内包含了一条条基于DSL(Domain Specific Language)语法的的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是形貌该层应当如何构建。通过这种形式,就使得构建的镜像更具备可重复性、透明性以及幂等性。
构建指令

Dockerfile 由一系列指令和参数构成,且每条指令都必须为大写,下令会按照在 Dockerfile 中的序次执行。常见的下令有下面这些:


  • FROM:用于指定底子镜像,必须为 Dockerfile 的第一条指令,如果不想指定底子镜像,可以用 scratch 取代,它代表不存在镜像。

    • 用法:
      1. FROM [镜像名/id]
      复制代码

  • RUN:用于执行下令行下令,支持 shell 和 exec 两种格式。考虑到每执行一次下令都对应着一次 docker commit 并建立新层,以是我们通常会用 && 来毗连一些相关操作,只管淘汰 RUN 的数量。

    • shell 格式:就像直接在下令行中输入下令一样,比方:
      1. RUN <命令>
      复制代码
    • exec 格式:用于调用可执行步伐,用法如下:
      1. RUN ["可执行文件", "参数1", "参数..."]
      复制代码

  • COPY:用于将构建上下文目次中源路径的文件/目次,复制到新的一层的镜像内的目标路径位置(复制后保存源文件的各种元数据,如读、写、执行权限、文件变动时间等)。

    • 用法:
      1. # 格式一
      2. COPY [--chown=<user>:<group>] <源路径>... <目标路径>
      3. # 格式二
      4. COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
      复制代码

  • ADD:用法与 COPY 一样,但是某些方面得到了加强,比方以下几个场景:

    • 源文件为 URL 时,会自动下载该文件放到目标路径中。
    • 源路径为压缩文件时,会自动解压缩到目标路径中。
    考虑到 ADD 会使镜像构建缓存失效,而且这些功能还需要配合 RUN 来修改权限、整理文件,其实大多数情况下照旧会通过 COPY + RUN 来实现。

  • CMD:用于指定默认的容器主历程的启动下令,格式与 RUN 类似。
  • ENTRYPOINT:与 CMD 一样都是在指定容器启动步伐及参数,但是其不是直接的运行其下令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 。其格式与 RUN 类似。

    • 其执行时如下:
      1. <ENTRYPOINT> "<CMD>"
      复制代码

  • VOLUME:用于指定某些目次挂载为匿名卷。

    • 用法:
      1. VOLUME ["<路径1>", "<路径2>"...]
      复制代码

  • ENV:用于设置环境变量。

    • 用法:
      1. # 格式一
      2. ENV <key> <value>
      3. # 格式二
      4. ENV <key1>=<value1> <key2>=<value2>...
      复制代码

  • ARG:用于构建参数,结果与 ENV 相同都能够构建环境变量,但是在容器运行后这些环境变量就会被删除(docker history 仍旧能望见)。

    • 用法:
      1. ARG <参数名>[=<默认值>]
      复制代码

  • EXPOSE:声明容器运行时提供服务的端口。需要留意的是,这只是一个声明,在容器运行时并不会因为这个声明应用就会开启这个端口的服务。

    • 用法:
      1. EXPOSE <端口1> [<端口2>...]
      复制代码

  • WORKDIR:用于指定工作目次。

    • 用法:
      1. WORKDIR <工作目录路径>
      复制代码

  • USER:用于指定当前的用户。

    • 用法:
      1. USER <用户名>[:<用户组>]
      复制代码



构建流程

Dockerfile 中每一个指令都会创建一个新的镜像层并对镜像进行提交,其构建流程如下:

  • Docker 借助底子镜像构建出一个容器。
  • 执行一条指令,对容器做出修改。
  • 执行类似 docker commit 的操作,提交一个新的镜像层。
  • Docker 借助刚刚提交的镜像层运行一个新容器。
  • 继承执行 Dockerfile 的下一条指令,继承重复步骤 2 开始的流程,直到所有指令全部执行完毕。
从这里也可以看到,docker 天生就具备了版本的机制,纵然因为某条下令失败而导致构建竣事。我们也能够获取到失败前的镜像,并基于这个镜像进行调试排错,而当下一次开始的时候,还能够从该镜像处构建(构建缓存机制,docker 会将之前的镜像层看作缓存)。


实例

讲完了根本下令和构建流程,现在我们就以之前的 CentOS 8 下的 nginx 镜像作为例子,来编写一个 Dockerfile。
首先我们需要创建一个目次,并在该目次下创建一个 Dockerfile 文件:
  1. mkdir demo
  2. cd demo
  3. touch Dockerfile
复制代码
  这个目次就是构建环境(build environment),Docker 则称此环境为上下文(context)大概构建上下文(build context)。Docker 会在构建镜像时将构建上下文和该上下文中的文件和目次上传到 Docker 守护历程。这样 Docker 守护历程就能直接访问用户想在镜像中存储的任何代码、文件大概其他数据。
  接着开始 Dockerfile 的编写:
  1. FROM centos
  2. RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* \
  3.         && sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* \
  4.         && yum install -y nginx \
  5.         && yum install -y net-tools
  6.     && yum install vim -y
  7. EXPOSE 80
  8. CMD ["nginx", "-g", "daemon off;"]
复制代码
这样一个简单的 Dockerfile 就编写完成了。


docker build

当 DockerFile 编写完毕后,我们就可以使用 docker build 下令来构建镜像了:
  1. docker build [选项] <上下文路径/URL/->
  2. # 例如
  3. docker build -t="orekilee/demo:nginx" .
复制代码
此时就会开始构建镜像,当构建完毕后,docker 会返回该镜像的 id。


推送镜像

当镜像构建完毕后,我们可以将镜像推送到 Docker Hub 上。
首先,我们需要使用 docker tag 下令标志一个本地镜像,将其归入到某一个堆栈中:
  1. docker tag [镜像名/镜像id][:标签名] [仓库地址][用户名]镜像名[:标签名]
复制代码
接着,使用 docker push 下令推送镜像:
  1. docker push [用户名/镜像名][:标签名]
复制代码
  需要留意的是,如果不加上堆栈名,则 docker 会认为当前需要 push 到 root 堆栈中,此时会因为不具备权限而被拒绝推送。
  

删除镜像

我们可以根据镜像名、镜像 id、镜像择要等信息,用 docker rmi 下令来删除镜像:
  1. docker rmi [name/id/digests]
复制代码
我们同样也能够通过组合多个下令来到达批量删除的目的,比方删除全部镜像:
  1. docker rmi `docker images
  2. -a -q`
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

火影

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表