安装配置

这里仅以CentOS 安装 Docker CE 举例说明。详见Docker 官方 CentOS 安装文档

准备工作

系统要求

Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10。 CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 overlay2 存储层驱动)无法使用,并且部分功能可能不太稳定。

警告:切勿在没有配置 Docker YUM 源的情况下直接使用 yum 命令安装 Docker.

卸载旧版本

旧版本的 Docker 称为 docker 或者 docker-engine,使用以下命令卸载旧版本:

  1. sudo yum remove docker \
  2. docker-client \
  3. docker-client-latest \
  4. docker-common \
  5. docker-latest \
  6. docker-latest-logrotate \
  7. docker-logrotate \
  8. docker-selinux \
  9. docker-engine-selinux \
  10. docker-engine

使用脚本安装(非生产环境)

对于个人测试,可以使用这个脚本自动化安装Docker:

  1. curl -fsSL get.docker.com -o get-docker.sh
  2. sh get-docker.sh

但是,需要注意, 这个脚本可能扰乱你的系统配置、安装及大量的(你可能用不到的)依赖,并且只能安装最新(可能未经充分测试的)版本的Docker , 所以不推荐在生产环境中使用。

使用 yum 安装

安装依赖包:

  1. sudo yum install -y yum-utils \
  2. device-mapper-persistent-data \
  3. lvm2

添加 yum 软件源:

  1. # 中国科学技术大学开源软件镜像源
  2. sudo yum-config-manager \
  3. --add-repo \
  4. https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
  5. # 官方源
  6. # sudo yum-config-manager \
  7. # --add-repo \
  8. # https://download.docker.com/linux/centos/docker-ce.repo

更新 yum 软件源缓存,并安装 docker-ce

  1. sudo yum makecache fast
  2. sudo yum install docker-ce

离线安装

以docker-ce-18.03.1为例:

  1. https://download.docker.com/linux/centos/7/x86_64/stable/Packages/这里找到对应rpm包
  2. 执行安装命令:rpm -ivh docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm
  3. 由于安装环境不同,可能会发现缺少一些相关依赖包(eg: libcgroup、libtool-ltdl、container-selinux)前往 https://pkgs.org/https://buildlogs.centos.org/ 下载对应依赖包,依次安装即可

启动 Docker CE

  1. sudo systemctl enable docker
  2. sudo systemctl start docker

建立 Docker 用户组

默认情况下,docker命令需要root权限,为了避免每次输入命令都要加sudo,可以将用户加入 docker 用户组:

  1. sudo groupadd docker
  2. sudo usermod -aG docker $USER

退出当前终端并重新登录,进行如下测试。

测试 Docker 是否安装正确

执行

  1. docker run hello-world

Docker会从官方仓库下载hello-world镜像并启动,如果一切正常的话会看到类似如下提示:

  1. Unable to find image 'hello-world:latest' locally
  2. latest: Pulling from library/hello-world
  3. ca4f61b1923c: Pull complete
  4. Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
  5. Status: Downloaded newer image for hello-world:latest
  6. Hello from Docker!
  7. This message shows that your installation appears to be working correctly.
  8. To generate this message, Docker took the following steps:
  9. 1. The Docker client contacted the Docker daemon.
  10. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
  11. (amd64)
  12. 3. The Docker daemon created a new container from that image which runs the
  13. executable that produces the output you are currently reading.
  14. 4. The Docker daemon streamed that output to the Docker client, which sent it
  15. to your terminal.
  16. To try something more ambitious, you can run an Ubuntu container with:
  17. docker run -it ubuntu bash
  18. Share images, automate workflows, and more with a free Docker ID:
  19. https://cloud.docker.com/
  20. For more examples and ideas, visit:
  21. https://docs.docker.com/engine/userguide/

镜像加速

鉴于国内网络问题,建议使用Docker中国或者其他国内镜像源。

修改(或新增)/etc/docker/daemon.json文件,添加:

  1. {
  2. "registry-mirrors": ["https://registry.docker-cn.com"]
  3. }

之后重启Docker使配置生效。

常用Docker操作

  1. # 查看docker版本
  2. docker version
  3. # 显示docker系统的信息
  4. docker info
  5. # 日志信息
  6. docker logs
  7. # 故障检查
  8. service docker status
  9. # 启动关闭docker
  10. sudo service docker start|stop

使用镜像

基本操作

以redis为例,我们从Docker Hub上获取官方镜像到本地:

Docker入门 - 图1

  1. docker pull redis

ps1:由于redis是官方源(Official),否则应该写完整的两段式仓库名 <用户名>/<软件名>,例如bitnami/redis。

ps2:此处没有指定镜像版本,默认会拉取redis:lastest镜像,指定版本应该写成例如:redis:5.0-rc5

查看已经下载的镜像:

  1. docker image ls
  2. # 会有类似如下显示
  3. REPOSITORY TAG IMAGE ID CREATED SIZE
  4. redis latest 5f515359c7f8 5 days ago 183 MB
  5. ......

更细节的显示可以使用docker image ls --format "{{.ID}}: {{.Repository}}"直接列出镜像ID和仓库名,

或者使用docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
以表格等距显示.

如果要删除某个镜像的话,可以使用docker image rm {IMAGE ID}|{REPOSITORY}命令,不要过先确保没有容器在使用这个镜像。

Dockerfile

除了引用制作好的镜像,我们也可以基于现有镜像定制新的镜像。定制所用的脚本文件就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction) ,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

我们新建一个空白文件,命名为 dockerfile,再文件中写入如下内容:

  1. FROM redis
  2. RUN mkdir redis
  3. WORKDIR redis
  4. COPY ./redis.conf /etc/
  5. CMD ["redis-server", "/etc/redis.conf"]

我们依次解释上面每一行:

  • FROM 就是指定 基础镜像 ,一个 DockerfileFROM 是必备的指令,并且必须是第一条指令。如果不以任何镜像为基础,那应该用FROM scratch作为起始指令。
  • RUN 是Dockerfile的核心指令,用于执行一条命令,由于Dockerfile 每一条指令都会新建一层,所以应该尽量将执行的内容写在一行(多行内容可以通过在末尾加\以表示未结束),它有两种写法:

    • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。
    • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。
  • WORKDIR 表示指定当前工作目录,相当于cd命令。
  • COPY 即复制文件到容器中,在这里是把redis.conf文件复制到容器的/etc目录下。
  • CMD 是启动程序的命令,写法和RUN相同,一般推荐使用exec格式。

常用Docker指令列表如下:

指令 含义 用法
FROM 指定基础镜像 FROM <基础镜像>
RUN 执行指令 RUN ["可执行文件", "参数1", "参数2"]
COPY 复制文件 COPY ["<源路径1>",... "<目标路径>"]
ADD 更高级的复制文件 ADD "<压缩文件>"
CMD 容器启动命令 CMD ["可执行文件", "参数1", "参数2"...]
ENTRYPOINT 入口点 ENTRYPOINT ["可执行文件", "参数1", "参数2"]
ENV 设置环境变量 ENV <key1>=<value1> <key2>=<value2>...
ARG 构建参数 ARG <参数名>[=<默认值>]
VOLUME 定义匿名卷 VOLUME ["<路径1>", "<路径2>"...]
EXPOSE 暴露端口 EXPOSE <端口1> [<端口2>...]
WORKDIR 指定工作目录 WORKDIR <工作目录路径>
USER 指定当前用户 USER <用户名>
HEALTHCHECK 健康检查 `HEALTHCHECK NONE [选项] CMD <命令>`
ONBUILD 构建下级镜像 ONBUILD <其它指令>
MAINTAINER 指定作者 ONBUILD <作者>

更多指令及用法请参照官方文档

如上,我们完成了一个使用自己配置文件的redis镜像的准备工作,之后依据这个Dockerfile进行构建:

  1. docker build -t redis_test:v0.1 .
  2. # 会有类似如下输出:
  3. Sending build context to Docker daemon 2.048 kB
  4. Step 1 : FROM redis
  5. ...
  6. ...
  7. Removing intermediate container 9cdc27646c7b
  8. Successfully built 44aa4490ce2c

docker build的用法为:

  1. docker build [选项] <上下文路径/URL/->

最后,可以使用docker push将你自己构建的镜像上传到仓库中,详细用法见官方文档 push

容器操作

容器启停

我们可以用这样的方式从之前的镜像启动一个容器:

  1. docker run -d --name some-redis redis

docker run的用法为docker run [选项] 镜像 [命令] [参数...],其中:

--name 指定容器的名称, -d 指定后台运行,其他常用参数包括-i 交互式操作,-t 使用终端(it一般同时使用),--rm 容器退出后随之将其删除,完整参数列表可以通过--help或者在线文档 docker run查看

由于我们是在后台运行,使用docker container ls来查看容器相关情况,如果要查看停止的进程,后面需要增加参数-a

  1. docker container ls
  2. # 会看到类似如下内容
  3. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  4. 77b2dc01fe0f redis:v2 redis-server redis.conf 'while tr 2 minutes ago Up 1 minute agitated_wright

使用docker container stop来结束容器的运行:

  1. docker container stop 77b2dc01fe0f

类似的,使用docker container start | restart | stop可以控制容器的启停,
使用docker container rm 来删除指定容器。

数据管理

之前提到过,随着容器的销毁,容器内的数据也会一同丢失。为了保存数据,Docker提供了两种方式(还有一种tmpfs mountsb不常用到):

方式1:数据卷(推荐)

数据卷 volume 是一个可供一个或多个容器使用的特殊目录,它不依赖于Unix文件系统,也拥有独立于容器的生命周期。

创建一个数据卷:

  1. docker volume create my-vol

查看数据卷及具体信息:

  1. # 查看所有的数据卷
  2. docker volume ls
  3. # 会看到类似如下内容
  4. local my-vol
  5. # -----------------------------------
  6. # 查看具体卷的信息
  7. docker volume inspect my-vol
  8. # 会看到类似如下内容
  9. [
  10. {
  11. "Driver": "local",
  12. "Labels": {},
  13. "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
  14. "Name": "my-vol",
  15. "Options": {},
  16. "Scope": "local"
  17. }
  18. ]

在用 docker run 的时候,增加 --mount 参数来使用数据卷,还是以启动redis为例,这里我们启动redis并且开启aof持久化:

  1. docker run -d \
  2. --name redis \
  3. --mount source=my-vol,target=/data \
  4. # -v my-vol:/data \
  5. redis \
  6. redis-server --appendonly yes

在这里redis产生的数据(/data目录下)被挂载到数据卷my-vol中。

我们也可以使用-v或者--volume语法,但是官方建议尽量使用--mount

同样使用inspect语法,我们可以查看redis容器的信息:

  1. docker inspect redis
  2. # 会看到类似如下内容
  3. "Mounts": [
  4. {
  5. "Type": "volume",
  6. "Name": "my-vol",
  7. "Source": "/var/lib/docker/volumes/my-vol/_data",
  8. "Destination": "/data",
  9. "Driver": "local",
  10. "Mode": "",
  11. "RW": true,
  12. "Propagation": ""
  13. }
  14. ],

方式2:绑定主机目录

我们也可以直接将容器的数据挂载 bind mount到宿主机的目录或文件 (而非由Docker创建的数据卷),以当前目录$(pwd)为例:

  1. docker run -d \
  2. --name redis \
  3. --mount type=bind,source="$(pwd)"/target,target=/data \
  4. redis \
  5. redis-server --appendonly yes

挂载单独文件的方法类似。

需要注意,本地目录必须存在,否则会报错。

区别

Docker入门 - 图2

Volumes是由Docker创建和管理,存储在宿主机固定位置(在linux上是/var/lib/docker/volumes/)。 非Docker应用程序不能改动这一位置的数据。 一个数据卷可以同时被挂载到几个容器中。即使没有正在运行的容器使用这个数据卷,它依然不会清除。可以通过docker volume prune清除不再使用的数据卷。

Bind mounts的数据可以存放在宿主机的任何地方。 非Docker应用程序可以改变这些数据。

使用网络

端口映射

docker run的时候使用-P(—publish-all)参数,随机映射一个 49000~49900 的端口到内部容器开放的网络端口。

或者使用-p ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort(—publish)来指定具体端口映射:

  1. docker run -d \
  2. --name some-redis \
  3. -p 6379:6379 \
  4. -p 127.0.0.1::16379/udp
  5. -p 127.0.0.1:80:80
  6. redis

这里我们分别将容器的6379端口映射到宿主机 任意ip的6379端口 ,容器的16379 udp端口映射到宿主机的 任意端口 ,容器的80端口映射到宿主机 对应的80端口

使用docker port 可以查看对应容器的全部端口映射。

容器互联

简单的容器互联可以通过--link 实现,但是 官方未来可能会删除这个参数 ,所以不展开。

最新的方式是搭建docker网络实现容器互联,先创建一个新的 Docker 网络:

  1. docker network create -d bridge my-net

这里的-d 参数指定网络类型,常用的只有bridge,其他的可能会在Swarm用到,如果不知道Swarm是什么就不用在意。

以redis客户端/服务端为例,分别在启动的时候将之加入my-net网络:

  1. docker run -d \
  2. --name redis-server \
  3. --network my-net \
  4. redis
  5. docker run -it \
  6. --rm \
  7. --name redis-client \
  8. --network my-net \
  9. redis redis-cli -h redis-server

可以看到成功进入redis-cli客户端,我们可以尝试info/keys *或者其他命令查看redis服务端运行情况。

延申

容器编排

面临一组容器配合使用的情况,例如一个包括负载均衡——网站后台——数据库的Web系统,我们可以使用Docker提供的Compose完成统一配置管理。它将提供相同功能的容器定义为服务service——以方便复用;将完整的容器组合组成项目project以方便统一管理。所有的配置通过一个yml文件即可实现。

Nvidia Docker

对使用GPU的容器,Docker提供Nvidia Docker以发挥GPU的运算性能。

基本要求如下:

  • GNU/Linux x86_64 with kernel version > 3.10
  • Docker >= 1.12
  • NVIDIA GPU with Architecture > Fermi (2.1)
  • NVIDIA drivers ~= 361.93 (untested on older versions)

详细安装使用见官方项目Wiki)

实例

项目地址: awesome-docker