Docker进阶
Docker 进阶
#Docker
说明
之前,基本是在单机上用 Docker,在不影响当前环境的前提下,创建和使用一些特殊环境。最近,涉及到多 Docker 的协作,比如:在同一服务器上启动和管理多个容器;在一台服务器上使用类似的镜像版本,在不同的机器之间复制镜像等等,积累了一些 docker 使用方法,和大家分享一下。
##环境搭建
要想了解整个流程,还是在自己机器上搭建环境,从头到尾过一遍,最为直接。
1 | $ sudo apt-get install docker.io |
安装好之后,就可以使用 docker 命令了。此时还只能用 root 身份,如果想让某个用户操作 docker,则需要将其加入 docker 组。
1 | $ sudo usermod -aG docker $your-user # 将新成员加入docker组 |
此时就进入了 docker 所启动系统命令行(后简称被 DOCKER 启动的系统为虚拟系统,运行 DOCKER 的计算机为本地系统,注意它和 virtual box 虚拟机不同),它是一个只是几十兆的小系统,此时可以用 apt-get 安装一些软件,来构造你的环境。
Docker 的 CS 模式
从上面的 service docker restart 可以看出,Docker 是 Client/Server 方式的,C/S 之间通过 socker 通讯。Service 端启在后台,client 端用 docker 命令与 server 通讯。
(1) 显示 Docker 系统信息
1 | $ docker info |
容器相关操作
我们先把 Docker 看成虚拟机,容器就是虚拟机的运行实例。
(1) 创建和启动容器
上面简单介绍了用 run 启动容器,下面来看看 run 的具体参数和使用方法
1 | $ docker run [OPTIONS] IMAGE [COMMAND] [ARG...] |
(2) 查看当前运行的容器
可以通过以下命令,查看正在运行的容器。
1 | $ docker ps |
此时,能看到正运行容器的一些信息,注意其中的 CONTAINER ID,之后我们会通过这个 ID 号操作指定的容器。
在搭建环境的最后一步,我们用 docker run 启动了一个容器,此时再开一个终端,用 docker ps 命令,就可以看到这个容器的存在。用 exit 退出后,再用 docker ps,则看不到该容器了。
(3) 在已运行的容器中执行命令
我们常使用 -d 参数后台启动容器,用 exec 可与正在运行的容器交互。
1 | $ docker exec -it CONTAINER_ID /bin/bash |
该命令可进入正在运行的 docker,常用它进入 docker 安装一些软件。
(4) 在虚拟系统与本地系统之间复制文件
1 | $ sudo docker cp HOST_PATH CONTAINER_ID:CONTAINER_PATH |
本地复制到容器
1 | $ sudo docker cp CONTAINER_ID:CONTAINER_PATH HOST_PATH |
容器复制到本地
(5) 查看某一容器的 log
1 | $ docker logs CONTAINER_ID |
查看 docker 中的 log 信息,比如我们用 docker 在后台启一个 jupyter,后来忘了 token 导致无法登录,就可以从 log 中找到。
(6) 停止运行中的容器
1 | $docker stop CONTAINER_ID |
(7) 删除容器
1 | $docker rm -f CONTAINER_ID |
删除之后,容器中的操作将不再保存。
run 包含建立(create)容器和启动(start)容器两步。对应的关闭时,也会为 stop 关闭和 rm 删除两步。如果 run 运行时不使用 -rm 参数,则停止运行后该容器不会被删除。需要用 rm 命令手动删除。
镜像 Image 相关操作
镜像一般指的是只读的数据包。容器是动态的,镜像是静态的,容器退出后该镜像依然存在,请注意,在容器中对虚拟系统的所做的修改并不会自动被保存在镜像之中。比如说,我下了N个软件,退出后,下次再 run 该镜像时,这些包就不存在了。
为什么不能像使用 virtual box 或者 vmware 虚拟机那样,一边运行一边保存呢?我觉得,是因为很多时候,在同一机器上可能基于同一个 image 启动多个 container,如果即时保存,image 里面倒底该保存哪个 container 呢?
(1) 查看镜像
可以通过以下命令,查看当前可用的 image。
1 | $ docker images |
注意 IMAGE ID 如果想要操作特定镜像,则需要使用该 ID。
(2) 以创建方式制作镜像
有时候我们需要保存安装的包和一些数据,以备下次使用。有两种方法:一种是用 build 方式创建新的镜像,一种是用 commit 在原有镜像的基础上修改后,保存成新的镜像。
1 | $ docker build -t REPOSITORY:TAG |
用当前目录的 Dockerfile 创建镜像,Dockerfile 文件可以指定基础镜像,安装包,环境变量等等。
(3) 以修改方式制作镜像
在一个容器中修改之后,可以通过 commit 把修改保存到镜像上。
1 | $ docker commit CONTAINER_ID REPOSITORY:TAG |
此时,用 docker images,就可以看到新的镜像了。新镜像只保存其基础版本的增补,并不会占太大空间,下次启动时,只需要指定 REPOSITORY:TAG 即可。
还可通过 TAG 命令修改其版本号
1 | $ docker tag 旧版本号 新版本号 |
相对来说,build 方法更加规范,能做出比较“干净”的镜像,我们知道这个镜像与基础版本有何不同,而 commit 相对比较随意,常用它来保存自己的工作现场。
(4) 删除镜像
先停掉(stop)启动的容器,然后运行 rmi 命令:
1 | $ docker rmi IMAGE_ID |
(5) 把一个机器上的镜像复制到另一台机器上
在要导出的机器 A 上,执行
1 | $ docker save -o 文件名 IMAGE的TAG |
在要导入的机器 B 上,执行
1 | $ docker load -i 文件名 |
Layer 层
做到这一步,有点好奇,docker 内部到底是如何管理基础版本和其上复杂分支的呢?先来看看元数据。
用以下命令,可获取容器或者镜像的元数据
1 | $ docker inspect CONTAINER_ID/IMAGE_ID |
此时,可以看到当前的信息,比如 IMAGE_ID 的 ID 及其 Parent,从而可确定其继承关系。在 Docker 内部,只保存各个版本之间的差异。
Layer 是 Docker 用来管理镜像层的中间概念,因为单个镜像层可能被多个镜像使用,所以 docker 把 layer 和 image 的概念分开,layer 存放了镜像层的 diff_id,size,parent_id 等内容。在同一个 Docker 版本管理系统中,只要 Layer 一致,就只保存一份。
默认情况下,镜像的存储路径为/var/lib/docker/aufs/,其中的 layers 文件夹存储的就是 layer 信息。
在机器A上,镜像的存储是增量的,如果用 save/load 方式复制到另一台机器 B 上,镜像会不会很大?答案是不会。镜像的存储是按 Layers 层层堆叠的,同一 layer 只存储一次,所以在向一台机器导入 image 时,会对比和保存新镜像和现存 layer 不同的部分。只是在复制过程中比较占空间。
参考
(1) Docker 命令大全
http://www.runoob.com/docker/docker-command-manual.html