镜像操作

相关概念

  • 仓库: 存放镜像文件的场所,仓库包含如下两种
    • DOcker仓库: 每个仓库集中存放某一类镜像, 这些镜像通过不同的标签区分; 例如存放Ubuntu镜像的仓库,其中包含了16.04, 18.04等多个版本
    • 仓库注册服务器: 存放仓库的地方, 里面往往包含了多个仓库
  • 镜像: 镜像类似与虚拟机镜像, 可以理解为一个只读模板
  • 容器: 容器类似一个轻量级的沙箱, Docker用来运行和隔离应用, 容器是从镜像创建的应用运行实例

镜像拉取

  • Docker镜像是运行容器的基础,如果运行容器时镜像不存在,Docker会尝试去Docker Hub公共注册服务器中的仓库中下载
  • 拉取命令格式
    • docker [image] pull NAME[:TAG]
    • image是本地的镜像名,用于区分镜像; NAME是镜像仓库名,TAG用来区分版本; 如果不指定TAG,默认拉去最近的镜像
    • 例如: docker pull ubuntu:18.04
  • 对于ubuntu镜像, 可能有多种不同的ubuntu镜像仓库, 所以拉取时,严格来说还需要指定仓库地址(Registry, 注册服务器), 默认使用官方Docker Hub服务; 例如
    • docker pull hub.c.163.com/public/ubuntu:18.04
  • 下载镜像过程中, 镜像文件一般由若干层(layer)组成, e9afc4f90ab0是层的唯一id,下载时会输出各层信息; 当不同的镜像包含相同的层时,本地仅存储了层的一份内容,减少存储空间
    1. mystack@mystack-pc:~$ sudo docker pull tomcat
    2. Using default tag: latest
    3. latest: Pulling from library/tomcat
    4. e9afc4f90ab0: Pull complete
    5. 989e6b19a265: Pull complete
    6. af14b6c2f878: Pull complete
    7. 5573c4b30949: Pull complete
    8. fb1a405f128d: Pull complete
    9. 612a9f566fdc: Pull complete
    10. cf63ebed1142: Pull complete
    11. fbb20561cd50: Pull complete
    12. 76c915a2cfb7: Pull complete
    13. a2c2864c3363: Pull complete
    14. Digest: sha256:11f247df062558074169fb92a54033ab2eb6563bda9765b3a9e53106db3c2f4a
    15. Status: Downloaded newer image for tomcat:latest
    16. docker.io/library/tomcat:latest

镜像查看

  • images / image ls

    • 查看本机下载的镜像
    • REPOSITORY: 镜像来自哪个仓库(例如tomcat仓库, 里面包含各种tag的tomcat)
    • TAG: 镜像标签
    • IMAGE ID: 镜像ID, 如果ID相同, 说明它们指向同一个镜像, 只是具有不同ID
    • CREATED: 最后更新时间
    • SIZE: 镜像大小, 镜像大小只是表示该镜像逻辑大小, 实际由于相同的镜像层本地只会存一份, 物理占用的存储空间会小于各个镜像大小之和
      1. mystack@mystack-pc:~$ sudo docker images
      2. REPOSITORY TAG IMAGE ID CREATED SIZE
      3. tomcat latest 6055d4d564e1 4 days ago 647MB
      4. mysql latest 9b51d9275906 4 months ago 547MB
  • tag

    • 添加镜像标签
    • docker tag IMAGE:TAG NEW_IMAGE:NEW_TAG
    • 通过tag可以添加一个本地镜像, 可以看到它们的ID相同,指向同一个镜像文件,只是别名不同而已
      1. mystack@mystack-pc:~$ sudo docker tag tomcat:latest mytomcat:1.0
      2. mystack@mystack-pc:~$ sudo docker images
      3. REPOSITORY TAG IMAGE ID CREATED SIZE
      4. mytomcat 1.0 6055d4d564e1 4 days ago 647MB
      5. tomcat latest 6055d4d564e1 4 days ago 647MB
      6. mysql latest 9b51d9275906 4 months ago 547MB
  • inspect

    • 获取镜像的详细信息, 包括制作者, 适应架构, 各层数字摘要等
    • docker [image] inspect NAME:TAG
      1. mystack@mystack-pc:~$ sudo docker inspect tomcat
      2. [
      3. {
      4. "Id": "sha256:6055d4d564e1d3a508e4781f2261f3620b3c43145d2286955060b6c4343a64bf",
      5. "RepoTags": [
      6. "mytomcat:1.0",
      7. "tomcat:latest"
      8. ],
      9. "RepoDigests": [
      10. "tomcat@sha256:11f247df062558074169fb92a54033ab2eb6563bda9765b3a9e53106db3c2f4a"
      11. ],
      12. "Parent": "",
      13. "Comment": "",
      14. ...
  • history

    • 查看镜像历史, 镜像文件由多个层组成, 通过该子命令可以获得各层内容
    • docker history NAME:TAG
    • 可以看到过长被截断了, 可以使用--no-trunc来输出完整内容
      1. mystack@mystack-pc:~$ sudo docker history tomcat
      2. IMAGE CREATED CREATED BY SIZE COMMENT
      3. 6055d4d564e1 4 days ago /bin/sh -c #(nop) CMD ["catalina.sh" "run"] 0B
      4. <missing> 4 days ago /bin/sh -c #(nop) EXPOSE 8080 0B
      5. <missing> 4 days ago /bin/sh -c set -e && nativeLines="$(catalin… 0B
      6. <missing> 4 days ago /bin/sh -c set -eux; savedAptMark="$(apt-m 20MB

搜寻镜像

  • search子命令可以用来搜寻Docker Hub中的镜像, docker search [option] keyword
  • 常用选项
    • -f, —filters filter: 过滤输出
    • —format string: 格式化输出
    • —limit int: 限制输出结果
    • —no-trunc: 不截断输出
  • 输出结果包含镜像名, 描述, 收藏数, 是否官方创建, 是否自动创建等
  • 搜索官方提供镜像: docker search --filters=is-official=true tomcat
  • 搜索收藏数超过4: docker search --filters=stars=4 tomcat
    1. mystack@mystack-pc:~$ sudo docker search tomcat
    2. NAME DESCRIPTION STARS OFFICIAL AUTOMATED
    3. tomcat Apache Tomcat is an open source implementati 2775 [OK]
    4. tomee Apache TomEE is an all-Apache Java EE certif 79 [OK]
    5. dordoka/tomcat Ubuntu 14.04, Oracle JDK 8 and Tomcat 8 base 54 [OK]
    6. bitnami/tomcat Bitnami Tomcat Docker Image 35 [OK]
    7. kubeguide/tomcat-app Tomcat image for Chapter 1 29

删除和清理镜像

  • 使用标签删除镜像
    • docker rmi IMAGE [IMAGE...] / docker image rm, IMAGE可以是标签或ID
    • 支持的选项
      • -f, -force: 强制删除, 即使有容器依赖它
      • -no-prune: 不要清理未带标签的父镜像
    • 这里可以看到docker image是一个子命令, 其下还有其他子命令, 例如docker image pull docker image rm docker image inspect
    • 如果删除使用tag产生的镜像, 即一个镜像有多个标签, 那么只会删除标签而已
    • 一般操作如果不加镜像版本时, 默认是latest, 如果不存在就会报错
    • 删除时, 会把镜像的每一层都删除掉 ```shell mystack@mystack-pc:~$ sudo docker rmi mytomcat Error: No such image: mytomcat

mystack@mystack-pc:~$ sudo docker rmi mytomcat:1.0 Untagged: mytomcat:1.0

mystack@mystack-pc:~$ sudo docker image rm tomcat Untagged: tomcat:latest Untagged: tomcat@sha256:11f247df062558074169fb92a54033ab2eb6563bda9765b3a9e53106db3c2f4a Deleted: sha256:6055d4d564e1d3a508e4781f2261f3620b3c43145d2286955060b6c4343a64bf Deleted: sha256:eaddaaaeeb4dfc083e045e780865653f50846e60ead2b9f0d1ea5e84831fc06d Deleted: sha256:328d1c4351076d38cda73e9a3eccd2352211d78b3667d7bea96fe91b32d7468d

  1. - 使用镜像ID删除镜像
  2. - 当使用`docker rmi`命令删除时, 如果后面使用镜像ID, 那么会尝试删除指向镜像的所有标签, 然后再删除镜像文件
  3. - 当有镜像创建的容器存在时, 镜像文件默认是无法删除的, 可以使用-f强制删除, 但是推荐先删除容器, 再删除镜像
  4. - 清理镜像
  5. - 使用Docker一段时间后, 系统可能遗留一些临时的镜像文件, 以及一些没有被使用的镜像, 通过`docker image prune`命令来处理
  6. - 常用选项
  7. - -a, -all: 删除所有无用镜像, 不仅包括临时镜像
  8. - -filter filter: 只删除特定镜像
  9. - -f, -force: 强制删除, 不提醒
  10. <a name="tiqkg"></a>
  11. ### 创建镜像
  12. - 基于已有容器创建
  13. - 该方法主要使用`docker [container] commit`命令
  14. - 命令格式为`docker [container] commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]`, 常用选项如下
  15. - -a, --author="": 作者信息
  16. - -c, --change=[]: 提交时执行Dockerfile指令,包括CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | ONBUILD | USER | VOLUME | WORKDIR
  17. - -m,--message="": 提交消息
  18. - -p,--pause=true: 提交时暂停容器运行
  19. - docker容器运行时,可以对容器做一些操作(比如添加文件之类的),这时该容器就已经和原镜像不一样了,可以基于该容器构建一个镜像
  20. - 构建命令:`docker commit -m "added a new file" -a "dongxinchen" 3be8b16e6a59 cdx_tomcat:1.0`
  21. - docker image相关命令
  22. - `docker image ls`
  23. - `docker image rm`
  24. - `docker image prune`
  25. - `docker image inspect`
  26. - `docker image pull`
  27. - 基于本地模板导入
  28. - 用户也可以直接从操作系统模板文件中导入一个镜像,使用`docker [container] import`命令
  29. - 格式:`docker [image] import [OPTIONS] file|URL|-[REPOSITORY[:TAG]]`
  30. - 基于Dockerfile创建
  31. - Dockerfile是一个文本文件,利用给定的指令描述基于某个父镜像创建新镜像的过程
  32. <a name="QdKng"></a>
  33. ### 存出和载入镜像
  34. - 存出镜像
  35. - 如果要导出镜像到本地文件,可以使用`docker [image] save`命令,支持`-o,-output string`参数,导出镜像到指定文件
  36. - 例如把镜像cdx_tomcat:1.0镜像为文件my_tomcat.tar`docker save -o my_tomcat.tar cdx_tomcat:1.0`
  37. - 载入镜像
  38. - 可以使用`docker [image] load`将导出的tar文件再导入到本地镜像库,支持`-i,-input string`参数,从指定文件导入镜像:`docker image load -i my_tomcat.tar` `docker image load > my_tomcat.tar`
  39. - 导入后的镜像标签和版本都是原来的cdx_tomcat:1.0
  40. <a name="PNaWH"></a>
  41. ### 上传镜像
  42. - 使用`docker [image] push`命令上传镜像到仓库,默认上传到Docker Hub官方仓库,需要登录,命令格式为`docker [image] push NAME[:TAG] | [REGISTRY_HOST[:REGISTRY_PORT]/]NAME[:TAG]`
  43. - 上传时,可以先给镜像添加新标签,然后再上传
  44. - `docker tag test:latest user/test:latest` `docker push user/test:latest`
  45. <a name="khnQG"></a>
  46. ## 容器操作
  47. <a name="aDNIm"></a>
  48. ### 创建容器
  49. - 容器是镜像的一个运行实例,镜像是只读文件,而容器带有运行时需要的可写文件层
  50. - 新建容器:使用`docker [container] create`创建一个容器,例如`docker container create -it tomcat`这样创建的容器处于创建状态,并未运行
  51. - 启动容器:使用`docker [container] start`启动一个容器
  52. - 新建并启动容器:使用`docker [container] run`等价于先执行create命令后执行start命令,执行该命令时
  53. - 使用伪终端进行交互:`docker run -it ubuntu:18.04 /bin/bash`
  54. - -t:让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上
  55. - -i:让容器的标准输入保持打开
  56. - 可以看到,容器里的进程很少,只启动了必要的进程而已,像是一个轻量级的虚拟机
  57. ```shell
  58. [root@izuf650sjqtwslsibvattnz ~]# docker exec -it 39d759326c55 /bin/bash
  59. root@39d759326c55:/usr/local/tomcat# ps -aux
  60. USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
  61. root 1 1.9 4.2 2535888 80092 pts/0 Ssl+ 10:32 0:02 /usr/local/openjdk-11/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.
  62. root 45 0.6 0.1 5740 2040 pts/1 Ss 10:35 0:00 /bin/bash
  63. root 50 0.0 0.0 9380 1464 pts/1 R+ 10:35 0:00 ps -aux
  • 守护状态运行:可以使用-d参数让容器以守护状态运行
  • 查看容器输出:使用docker [container] logs命令
    • -details:打印详细信息
    • -f,-follow:保持持续输出
    • -since string:输出从某个时间开始的日志
    • -tail string:输出最近若干日志
    • -t,timestamps:现实时间戳
    • -until string:输出某个时间之前的日志
    • docker logs ce55f5ewf15

停止容器

  • 暂停容器
    • 使用docker [container] pause CONTAINER [CONTAINER...]命令暂停一个运行的容器
    • 处于paused状态的容器可以使用docker [container] unpause CONTAINER [CONTAINER...]恢复运行
  • 终止容器
    • 可以使用docker [container] stop终止一个容器,命令格式为docker [container] stop [-t|--time[=10]] [CONTAINER...]
    • 该命令向容器发送SIGTERM信号,超时一段时间后发送SIGKILL终止容器
    • 执行后使用docker container prune命令来清除所有处于停止状态的容器
    • 也可以通过docker [container] kill直接发送SIGKILL信号终止容器
    • 当Docker容器中指定的应用终结时,Docker容器也会终止
    • 处于终止状态的容器,可以使用docker [container] start来重新启动
    • docker [container] restart命令会先将容器终止,再重新启动

进入容器

  • 使用-d参数,容器启动后会进入后台,用户无法看到信息
  • attach命令
    • 格式docker [container] attach [--detach-keys[=[]]] [--no-stdin] [--sig-proxy[=true]] CONTAINER
    • --detach-keys[=[]]指定退出attach模式的快捷键序列,默认是CTRL-p,CTRL-q
    • --no-stdin=true|false是否关闭标准输入,默认打开
    • --sig-proxy=true|false是否代理收到的系统信号给应用进程,默认true
    • 然而使用attach命令有时不方便,当多个窗口同时attach同一个容器时,所有窗口会同步显示,一个窗口命令阻塞时,其他窗口也无法使用
  • exec命令
    • Docker1.3开始,提供了一个exec命令,可以在运行中容器内直接执行任意命令
    • docker [container] exec [-d|--detach] [--detach-keys[=[]]] [-i|--interactive] [--privileged] [-t|--tty] [-u|--user[=USER]] CONTAINER COMMAND [ARG...]
    • 比较重要的参数
      • -d,—detach:在容器中后台执行命令
      • —detach-keys=””:指定将容器切回后台的按键
      • -e,—env=[]:指定环境变量列表
      • -i,—interactive=true|false:打开标准输入接收用户输入命令,默认为false
      • —privileged=true|false:是否给执行命令以最高权限,默认false
      • -t,—tty=true|false:分配伪终端,默认false
      • -u,—user=””:执行命令的用户名或ID
    • 进入容器并启动bash:docker exec -it ajfiweofew /bin/bash

删除容器

  • 使用docker [container] rm命令删除处于终止或退出状态的容器
  • 格式docker [container] rm [-f|--force] [-l|--link] [-v|--volumes] CONTAINER
  • 支持的选项
    • -f,--force=false是否强行终止并删除运行中的容器
    • -l,--link=false删除容器的链接,但是保留容器
    • -v,--volumes=false删除容器挂载的数据卷

导入和导出容器

  • 有些时候,需要把容器从一个系统迁移到另一个系统,此时可以利用容器的导入导出功能
  • 容器导出
    • 使用docker [container] export命令,无论容器是否在运行,都可以导出
    • 例如docker export -o test_tomcat.tar bjio56161b
  • 容器导入
    • 使用docker [container] import命令,用户可以通过-c,—change=[]选项在导入同时执行对容器进行修改的Dockerfile指令
    • 例如docker import test_tomcat.tar - test/ubuntu:v1.0

查看容器

  • 查看容器详情
    • 使用docker container inspect [OPTIONS] CONTAINER [CONTAINER...]
  • 查看容器内进程
    • 使用docker [container] top [OPTIONS] CONTAINER
  • 查看统计信息
    • 使用docker [container] stats [OPTIONS] [CONTAINER...]显示CPU,内存,网络等信息
    • -a,-all:输出所有容器信息,默认仅在运行中的信息
    • -format string:格式化输出信息
    • -no-stream:不持续输出,默认实时输出
    • -no-trunc:不截断输出

其他容器命令

访问仓库

Docker Hub公共仓库镜像市场

  • 仓库是集中存放镜像的地方,要区分仓库和注册服务器(Registry),注册服务器是存放仓库的具体服务器,一个注册服务器可以包含多个仓库,每个仓库可以下载某一类镜像
  • 因此,仓库可以被看作一个具体的项目或目录,例如对于private-docker.com/ubuntu来说,private-docker.com是注册服务器地址,ubuntu是仓库名
  • Docker Hub是Docker提供的公共镜像库
  • 登录:使用docker login命令输入用户名,密码,邮箱完成注册和登录;注册成功后,本地用户目录下会自动创建.docker/config.json文件,保存用户认证信息,登录成功后,就可以制作上传个人镜像了
  • 基本操作

    • docker search查找镜像
    • docker pull拉取镜像
    • docker push推送本地镜像到Docker Hub
    • 如下查找到的镜像中,分为两类
      • 一种是类似centos的基础镜像,称为根镜像,往往由官方制作,以单个单词为名称
      • 一种是ansible/centos7-ansible的镜像,代表是用户ansible维护的,以user_name/centos的形式命名;表明是该用户仓库下的镜像
        1. [root@izuf650sjqtwslsibvattnz ~]# docker search centos
        2. NAME DESCRIPTION STARS OFFICIAL AUTOMATED
        3. centos The official build of CentOS. 6085 [OK]
        4. ansible/centos7-ansible Ansible on Centos7 131 [OK]
        5. consol/centos-xfce-vnc Centos container with "headless" VNC session 117 [OK]
        6. jdeathe/centos-ssh OpenSSH / Supervisor / EPEL/IUS/SCL Repos - 115 [OK]
        7. centos/systemd systemd enabled base container. 85 [OK]
        8. centos/mysql-57-centos7 MySQL 5.7 SQL database server 77
        9. imagine10255/centos6-lnmp-php56 centos6-lnmp-php56 58 [OK]
        10. tutum/centos Simple CentOS docker image with SSH access 47
  • 自动创建:可以自动跟随项目代码变更而重新构建镜像

第三方镜像市场

  • 如果使用第三方仓库注册服务器,则需要在镜像名前面添加具体地址
  • 格式为index.tenxcloud.com/<namespace>/<repository>:<tag>
  • 例如docker pull index.tenxcloud.com/docker_library/node:latest

搭建私有镜像仓库Registry

  • 使用Registry镜像搭建docker run -d -p 5000:5000 registry
  • 默认创建的容器,仓库会被放在容器的/var/lib/registry目录下,如果没有进入到容器中,无法使用该目录,可以通过-v参数将镜像文件夹存放到本地路径
  • docker run -d -p 9988:5000 -v /opt/data/registry:/var/lib/registry registry
  • 接下来就可以使用上传和下载镜像的命令了

Docker数据管理

数据卷

  • 生产中,往往需要对数据进行持久化,或者在多个容器中进行数据共享,容器中管理数据由两种方式
    • 数据卷(Data Volumes):容器内数据直接映射到本地主机环境
    • 数据卷容器(Data Volumes Containers):使用特定容器维护数据卷
  • 数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似Linux中的mount行为
  • 创建数据卷:通过volume子命令来管理数据卷,通过docker volume create -d local test创建数据卷,test数据卷会被创建在/var/lib/docker/volumes
  • 其他命令,docker volumes还支持inspect(查看详细信息),ls(列出已有数据卷),prune(清理无用数据卷),rm(删除数据卷)等

绑定数据卷

  • 除了使用volume子命令管理数据卷外,还可以在创建容器时将本机的目录挂载到容器内作为数据卷,这种创建数据卷的形式称为绑定数据卷
  • 使用docker [container] run命令时,使用-mount选项来使用数据卷,该选项支持三种类型数据卷
    • volume:普通数据卷,映射到主机/var/lib/docker/volumes路径下
    • bind:绑定数据卷,映射到主机指定目录下
    • tmpfs:临时数据卷,只存在内存中
  • 下面使用training/webapp镜像创建一个web容器,并创建一个数据卷挂载到容器的/opt/webapp目录
  • docker run -d -P --name web --mount type=bind, source=/webapp, destination=/opt/webapp training/webapp python app.py
  • 该命令等价于
  • docker run -d -P --name web -v /webapp:/opt/webapp training/webapp python app.py
  • 这样,在测试时,可以直接在本地数据卷修改数据,容器及时更新
  • Docker挂载的数据卷默认权限为rw,可以通过ro指定为只读
  • docker run -d -P --name web -v /webapp:/opt/webapp:ro training/webapp python app.py

    数据卷容器

  • 如果要在多个容器间共享数据,最简单的方式是使用数据卷容器,数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载


  • Run命令常用参数

  • -d,--detach=true|false:容器在后台运行,默认是在前台,即信息都会输出到标准流

  • -p,--publish=[]:指定如何映射本到本地主机端口,例如-p hostPort:containerPort
  • -v|--volume[=[[HOST-dir:]container-dir[:options]]]:挂在主机上的文件卷到容器内
  • -P,--publish-all=true|false:通过NAT机制将容器标记暴露的端口自动映射到本地主机的临时端口,加了这个参数后使用netstat -anp | grep proxy命令可以看到打开了一个端口;如果没有加-P或-p,那么在本机不会暴露任何端口
  • --name="":指定容器的别名
  • -i,--interactive=true|false:保持标准输入打开,默认为false;就是把容器的输入重定向到当前标准输入,这样就可以和容器交互了;如果只用了-t,没有-i,那么只代表分配一个伪终端,这时会进入这个伪终端,但是无法输入,因为伪终端的输入和当前标准输入未绑定
  • -t,--tty=true|false:分配一个伪终端,如果只使用了-i,没有使用-t,那么代表绑定了标准输入流,但是并没有打开一个新终端。这时的终端默认是?,即不属于任何终端,但是可以进行交互输入。
    • 下面可以看到,由于多次执行了-t分配伪终端,但是没有绑定输入,所以无法退出该终端,导致伪终端数目一直增加
    • 因此,对于那些运行完就会退出的容器,可以分配一个伪终端给他,但是不绑定输入流,这样就可以一直运行了

docker1.png
docker2.png