docker基础和使用

1 docker的基本概念和框架

1.1 Docker组成

docker基本架构

  • Docker Client客户端
  • Docker Daemon守护进程
  • Docker Image镜像
  • Docker Container容器
  • Docker Registry仓库,有公有和私有仓库

docker引擎

docker引擎


1.2 Docker容器相关技术

(1) Namespaces命名空间

  • 对于编程语言来说:封装 —> 代码隔离。
  • 对于操作系统来说:系统资源的隔离,系统资源包括进程、网络、文件系统等。

docker的6种命名空间:

名称 说明
PID (Process ID) 进程隔离
NET (Network) 管理网络接口
IPC (InterProcess Communication) 管理跨进进程通信的访问
MNT (Mount) 管理挂载点
UTS (Unix Timesharing System) 隔离内核和版本标识
USER 用户

这6种资源是怎么管理起来?答:使用Control groups 控制组,


(2) Control groups 控制组

控制组是可以限制、记录、隔离进程使用物理资源的机制,用来分配资源,就是为了Docker而生的。

控制组功能:

名称 说明
资源限制 例如为进程设置内存限制,当内存达到限制值时,禁止申请新进程
优先级设定 可以设定哪些进程组使用更多CPU、磁盘IO资源
资源计量 可以计算进程组使用了多少资源
资源控制 可以将进程组挂起和恢复


从Control groups 功能中可以知道有哪些Docker容器的能力。

名称 说明
文件系统隔离 每个容器都有自己的root文件系统
进程隔离 每个容器都运行在自己的进程环境中
网络隔离 容器间的虚拟网络接口和IP地址都是分开的
资源隔离和分组 使用Control groups将CPU和内存之类的资源独立分配给每个Docker容器



2 docker安装和启动

2.1 docker安装

docker 要求centOS系统的内核版本高于3.10,查看本页面的前提条件来验证你的centOS版本是否支持docker,查看当前系统的内核版本:

uname -r

在centos系统安装docker很简单,两行命令就可以了。

# 安装软件
yum install -y yum-utils device-mapper-persistent-data lvm2

# 添加yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 查看可安装的版本
yum list docker-ce --showduplicates | sort -r

# 安装最新版本
yum install -y docker-ce

# 设置系统开机自动启动docker
systemctl enable docker

# 启动docker服务
systemctl start docker

# 查看docker信息
docker info


2.2 docker启动失败解决方法

通过命令systemctl status docker查看启动失败信息,如果错误信息为++Error starting daemon: SELinux is not supported with the overlay2 graph driver on this kernel++, 说明SELinux不支持这个内核上的OrthALA2图形驱动程序。

解决方法:重新编辑docker配置文件

vi /etc/sysconfig/docker

把OPTIONS选项里的–selinux-enabled改为–selinux-enabled=false,然后重启docker。

systemctl restart docker


2.3 添加用户组

安装完后只能在root用户才有权限执行docker命令,为了让其他用户也拥有权限,需要把用户添加到添加到docker用户组中。

# 添加docker用户组
groupadd docker

# 把用户vison添加到用户组docker
gpasswd -a vison docker

# 重启docker服务
systemctl restart docker

# 切换当前会话到新组
newgrp - docker


2.4 docker守护进程启动选项

docker -d [OPTIONS]

(1) 运行相关配置:

  • -D表示debug模式启动;
  • -g表示目录,默认值为/var/lib/docker;
  • -l表示日志级别,默认值为”info”;
  • -p表示docker的pid文件位置,默认值为/run/docker.pid
  • –label name=dockerServer02,docker启动时名字


(2) 服务相关配置:

  • -G表示运行的用户组,默认为用户组docker
  • -H表示接受客户端连接方式,支持三种方式,tcp://host:port、fd://sockfd、unix:///path,可以同时设置多种连接方式,默认值unix:///run/docker.sock
  • tls表示安全选项


(3) remotAPI相关配置

  • –api-enable-cores=false表示是否开启api访问


(4) 存储相关配置:

  • -s表示存储的驱动
  • -selinux-enabled=false
  • –storage-opt=[]


(5) 仓库相关配置:

  • –insecure-registy=[]
  • –rigisty-mirror=[]


(6) 网络相关配置:

  • -b表示网桥
  • –bip=“”
  • –dns=“”
  • –ip=0.0.0.0

通过修改docker配置文件/etc/sysconfig/docker设置docker守护进程启动选项,修改完后需要重启docker使配置生效。


2.5 修改docker镜像存储位置

默认docker镜像存储位置是/var/lib/docker,自定义镜像存储位置,docker启动配置文件地址在不同版本Linux可能不一样:

  • ubuntu:/etc/default/docker
  • centos7:/etc/docker/
# 打开配置文件
vim /lib/systemd/system/docker.service

    # 在ExecStart=/usr/bin/dockerd后面添加参数
    --graph=/data/docker --storage-driver=overlay

# 重启docker
systemctl daemon-reload
systemctl restart docker

# 查看镜像位置是否修改
docker info | grep Dir


2.6 docker命令自动补全

Linux系统许多命令都会提供自身的命令补齐脚本,在安装命令时会自动安装自动补齐脚本在/usr/share/bash-completion/completions/目录下。

# 检查是否已安装bash_completion,自动补齐需要依赖工具bash-complete
ls /usr/share/bash-completion/bash_completion

# 如果bash-complete不存在,先安装工具
yum -y install bash-completion
# 刷新
source /usr/share/bash-completion/bash_completion

# 检查docker自动补全脚本是否存在,一般安装完dock都有
ls /usr/share/bash-completion/completions/docker
# 如果存在就可以实现docker命令自动补全了



3 docker基本操作

常用的docker操作命令:

名称 说明
docker search Search the Docker Hub for images
docker pull Pull an image or a repository from a registry
docker images List images
docker create Create a new container
docker start Start one or more stopped containers
docker run Run a command in a new container
docker attach Attach to a running container
docker ps List containers
docker logs Fetch the logs ofa container
docker restart Restart a container
docker stop Stop one or more running containers
docker kill Kill one or more running container
docker rm Remove one or more containers


3.1 启动容器

(1) 启动命令行容器

docker run IMAGE [COMMAND] [ARG...]

# IMAGE表示镜像名称;COMMAND表示在容器中执行的命令;ARG表示命令参数。

# 示例:
docker run centos echo 'hello world'

在新容器中执行完命令后,容器也就停止了。


(2) 启动交互式容器

docker run -i -t IMAGE /bin/bash

# -i表示始终打开标准输入;-t表示打开一个伪终端

# 示例:
docker run -it centos /bin/bash

进入终端后,如果执行exit命令,则交互式的容器也就结束了。


(3) 启动时自定义容器名字


docker run -i -t --name=xxx IMAGE /bin/bash

# --name表示自定义的容器名称,可以使用自定义的名字替换比较难记的容器ID了。

# 示例:
docker run -it --name=centos01 centos /bin/bash


(4) 启动守护式容器

  • 执行docker run -it IMAGE COMMAND命令进入容器终端后,按下Ctrl+P和Ctrl+Q组合键,容器就以守护进程在后台方式。

如果需要再次进入容器终端,使用命令

docker attach 容器名


  • 主要的守护式启动容器
docker run -d <镜像名> [命令]

# -d表示以守护进程方式启动。

# 示例:
docker run -d centos /bin/bash -c "for i in {1..3600}; do echo "$i"; sleep 1; done"

注意:如果容器里面的程序结束了,容器也就结束了。


(5) 启动时限定容器资源

使用docker run –help查看参数,

# 关于内存分配参数
    --memory <bytes>
    --memory-swap <bytes>
    如果只指定--memory参数,那么--memory-swap的默认值和--memory一样。
    # 示例:
    docker run -it --memory 500M centos /bin/bash

# 关于cpu参数
    --cpus decimal
    --cpu-shares int
    其中--cpu-shares表示cpu分配权重,在同一宿主机启动多个容器时,权重越大,占cpu资源的比重也越大。

    # 示例:
    docker run -it --cpu-shares 10 --name centos01 centos /bin/bash
    docker run -it --cpu-shares 5 --name centos02 centos /bin/bash

可以安装stress工具压测容器资源。


(6) 启动时添加环境

docker run -d -e <key=value> <镜像名> [命令]

# 示例:
docker run -d -e MYSQL_ROOT=root -e MYSQL_ROOT_PASSWORD=123456 mysql


(7) 启动时添加自动删除参数

docker run -it --rm <镜像名> [命令]

#示例:
docker run -it --rm busybox /bin/bash


3.2 重新启动容器

docker <start> [-i] <NAMES>

# -i表示启动容器并进入终端模式;NAMES表示容器名。

# 示例:
docker start centos01
docker start -i centos01


3.3 在运行中的容器启动新进程

docker exec [-d] [-i] [-t] 容器名 [COMMAND] [ARG...]

# -d表示以守护进程方式启动;-i表示始终打开标准输入;-t表示打开一个伪终端,参数和docker run命令类似。

# 示例:
docker exec -it centos01 /bin/bash


3.4 查看容器列表

docker ps [-a] [-l]

# -a表示列出所有的容器;-l表示最新创建的容器。

# 示例:
docker ps # 列出正在运行的容器
docker ps -a # 列出所有容器,包括运行或停止的容器

容器列表各列的意义:

名称 说明 例子
CONTAINER ID 启动时为容器分配的唯一id 196f21865713
IMAGE centos
COMMAND 启动容器执行的命令 ”/bin/bash”
CREATED 启动容器时间 42 seconds ago
STATUS docker状态 Up 42 seconds
PORTS 端口映射 0.0.0.0:32782->80/tcp
NAMES 为容器自动分配的名字,可以自定义命名 amazing_ptolemy


3.5 查看容器或镜像详细信息

docker inspect [OPTIONS] CONTAINER|IMAGE

# CONTAINER可以是容器id或容器名字;IMAGE可以是镜像名或镜像id

# 示例:
docker inspect centos01
docker inspect 04111d337024


3.6 停止正在运行的容器

docker <kill | stop> <NAMES>

# kill表示马上结束容器;stop表示想容器发送停止信号,需要等待一会才停止容器。

# 示例:
docker kill centos01
docker stop centos01
docker stop $(docker ps -q)   # 停止所有容器


3.7 删除容器

docker rm <CONTAINER ID | NAMES...>

# 只能删除已经停止的容器,不能删除正在运行的容器。

# 示例:
docker rm centos01
docker rm b761c41c9a0a 317c1b786fb2
docker rm $(docker ps -aq)  # 删除所有docker
docker rm -f centos01


3.8 查看容器日志

docker logs [-f] [-t] [--tail] 容器名

# -f表示一直监听日志;-t表示在返回结果上加上时间;--tail可以指定显示最新的行数。

# 示例:
docker logs -f centos01
docker logs -ft centos02
docker logs --tail 10 centos02

可以使用命令docker top <容器名>来查看容器进程运行情况。


3.9 查看容器的ip地址

 docker inspect --format '{{ .NetworkSettings.IPAddress }}' <容器名>

# 示例:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' centos01

# 查看docker run命令启动的所有容器的ip地址
docker inspect -f '{{.Name}} - {{.NetworkSettings.IPAddress }}' $(docker ps -aq)

# 查看docker-compose命令启动的所有容器的ip地址
docker inspect -f '{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)

# 如果嫌弃命令输入麻烦,可以自定义命令获取容器ip地址

    # 创建文件
    mkdir ~/scripts
    vim ~/scripts/get-container-ip.sh

    # 文件内容如下:
    #!/bin/bash

    sudo docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $1

    # 把脚本文件改为可执行权限
    chmod +x ~/scripts/get-container-ip.sh

    # 添加快捷命令
    vim ~/.bashrc

    # 添加内容
    alias docker-ip='sh ~/scripts/get-container-ip.sh'

    # 查看容器ip
    docker-ip <容器名或id>


3.10 容器的端口映射

docker [-P] [-p]

# -P表示容器暴露的所有端口都进行映射;-p表示指定映射容器的那些端口

# 示例:
docker run -P -it centos01 /bin/bash  # 映射所有端口
docker run -p 80 -it centos01 /bin/bash  # 映射80端口

指定映射端口有四种形式:

格式 说明
docker run -p 80 … 只指定容器端口,而宿主机端口是随机映射的。
docker run -p 8080:80 … 一一对应端口映射
docker run -p 0:0:0:0:80 … 指定ip和容器端口
docker run -p 0.0.0.0:8080:80 … 指定ip和端口和宿主机端口映射

使用命令docker port <容器名称>查看端口映射。


3.11 docker登陆

# 登陆方式一:
docker login -u username -p xxxxxx

# 登陆方式二:
cat pwd.txt | docker login -u username --password-stdin


3.12 复制容器里的文件到宿主机

docker cp <容器id或名称>:<目录或文件> <宿主机目录>

# 示范:

docker cp cd6685e8656f:/tmp/app.log /tmp


3.13 使用docker搭建博客wordpress

docker上wordpress地址:https://hub.docker.com/_/wordpress/

docker上mysql地址:https://hub.docker.com/_/mysql/

# 启动mysql容器
docker run -d --name mysql -v /data/docker/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=wordpress mysql

# 启动wordpress容器
docker run -d --name wordpress -e WORDPRESS_DB_HOST=mysql:3306 -p 8080:80 --link mysql wordpress



4 docker镜像与仓库

什么是镜像

通过命令docker info查看容器统计信息、硬件信息、软件信息,从信息中得到docker的根目录是/var/lib/docker,根目录下有许多目录。

.
├── containers # 容器存放目录
├── image  # 镜像存放目录
├── network  # 网络
├── overlay2
├── plugins
├── swarm
├── tmp
├── trust
└── volumes


4.1 查看镜像列表

docker images [-a] [-f] [--no-trunc] [-q] [仓库]

# -a表示所有选项,包括显示中间层镜像;-f表示显示时的过滤条件;--no-trunc表示是否显示完整的id名;-q表示只显示镜像唯一id。

# 示例:
docker images   # 显示已经安装的docker镜像,不包括中间层镜像
docker images -a
docker images --no-trunc
docker images -q centos
名称 说明 示例
REPOSITORY 仓库名 docker.io/nginx
TAG 标签名 latest
IMAGE ID 镜像id 5182e96772bf
CREATED 创建时间 4 days ago
SIZE 镜像大小 200 MB


(1) Repository和Registry区别

按照Docker的logo来看Repository是集装箱,Registry是鲸鱼。

Repository:本身是一个仓库,这个仓库里面可以放具体的镜像,是指具体的某个镜像的仓库,比如Centos下面有很多个版本的镜像,它们共同组成了Centos的Repository。

Registry:镜像的仓库,比如官方的是Docker Hub,它是开源的,也可以自己部署一个,Registry上有很多的Repository,Redis、Centos、MySQL等等Repository组成了Registry。


(2) TAG

镜像的标签,在同一个仓库中,不同的镜像是通过标签来区分的,仓库名加上标签名组成一个完整的镜像名,这个镜像名对应一个唯一的id,例如centos:7.2,可以对应同样一个镜像文件,根据不同的需求打上不同的标签。


4.2 删除镜像

docker rmi [-f] [--no-prune] <IMAGE>

# -a表示强制删除镜像;--no-prune表示保留镜像中被打标签的副镜像;IMAGE是镜像名字,可以说仓库名:标签名,也可以是短镜像id或长镜像id名字,注意不同标签可以对应统一镜像id,使用删除镜像id方式会把所有对应的标签名的镜像都删除。

# 示例:
docker rmi -f centos:7.2 centos:6.9
docker rmi --no-prune 5182e96772bf

# 删除busybox所有镜像,如果强制删除添加-f参数
docker rmi $(docker images -q busybox)

# 删除标签为none的镜像,如果强制删除添加-f参数
docker rmi $(docker images | grep "<none>" | awk '{print $3}')

# 删除同一仓库镜像,如果强制删除添加-f参数
docker rmi $(docker images | grep "zhufuyi" | awk '{print $3}')


4.3 查找镜像

查找镜像有两种方式,一是去官方网站docker hub搜索,需要注册,二是使用命令行搜索。

docker search [OPTIONS] TERM

# --automated表示显示自动化构建出的镜像;--no-trunc表示不截断方式显示输出;-s表示显示结果的最低星数量。

# 示例:
docker search centos
docker search --automated centos
docker search --no-trunc centos
docker search -s 100 centos


4.4 获取镜像

docker pull [OPTIONS] NAME [:TAR]

# -a表示下载所有匹配到名字镜像,下载docker hub上镜像可能会很慢。

# 示例:
docker pull centos


4.5 上传镜像

docker push NAME [:TAR]

docker不会整个镜像上传,只上传有变化的部分。

# 示例:
docker push zhuyasen/centos


4.6 构建镜像

构建镜像有两种方式,一是通过容器构建镜像,二是通过dockerfile构建镜像。

(1) 通过容器构建镜像

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAR]]

# -a表示填写镜像的作者名字和联系方式;-m表示镜像构建的信息;-p表示构建镜像过程中是否暂停运行中的容器。

# 运行docker run后,然后进入该容器里安装一些软件 ,最后使用这个容器创建新的镜像。

# 构建镜像成功后返回镜像id,可以通过docker images命令查看。

# 示例:
docker commit -a 'vison' -m 'install app' mynginx vison/nginx

# 运行刚构建完成的镜像
docker run -d -p 80 --name myNginx01 vison/nginx nginx
#注:nginx配置文件已设置了daemon off;


(2) 通过dockerfile构建镜像

镜像构建过程:

  • 从基础镜像运行一个容器。
  • 执行一条指令,对容器做出修改。
  • 执行类似docker commit的操作,提交一个新的镜像。
  • 基于刚提交的镜像运行一个新的容器。
  • 执行dockerfile中的下一条指令,直到所有指令执行完成。
docker build [OPTIONS] PATH | URL

# -t表示指定镜像名字;
# --force-rm表示总是删除掉中间环节的容器;
# --no-cache表示将不使用Build Cache构建镜像;
# --pull表示总是尝试pull镜像的最新版本;
# -rm表示即整个构建过程成功后删除中间环节的容器,默认为true;


# 一个简单的dockerfile文件内容如下:
FROM centos
MAINTAINER vison "vison@126.com"
RUN for i in {1..3600}; do echo "$i"; sleep 1; done
EXPOSE 80

# 示例:
docker build -t vison/nginx ~/work/docker/test

# 查看镜像构建过程命令
docker history vison/nginx

# 查看镜像列表
docker images

docker build执行dockerfile里的指令都会生成一个中间层的镜像和运行的容器,构建过程中会删除生成的中间层容器,但不删除中间层镜像,可以使用中间层镜像运行docker run命令启动一个容器,通过中间层镜像运行的容器可以查看每一步镜像构建后的实际状态,构建镜像出错时方便调试定位到哪一个中间层出错。还有一个非常重要的功能就是构建缓存,由于第一次构建过程中对各个中间层镜像进行了缓存,下一次构建新的镜像时优先使用缓存,使得构建速度非常快。但是有些情况不想使用缓存,例如执行update、wget等操作时,希望每次获取都是最新的数据,可以指定构建镜像时不使用缓存,例如docker build –no-cache …


(3) 查看新镜像的构建过程列表

docker history <镜像名或id>


4.7 dockerfile文件语法命令

(1) FROM命令,支持两种形式,构建新镜像使用的基础镜像,所以源镜像必须存在,并且是非注释的第一条命令。

FORM <image>
FORM <image>:<tag>

# 示例:
FROM nginx


(2) LABEL和MAINTAINER命令,MAINTAINER用来指定构建镜像的作者信息,新版本docker已经摒弃,使用LABEL可以实现,LABEL保存key=value键值对元数据。

# 示例:
# MAINTAINER "vison vison@126.com"
LABEL maintainer="vison vison@126.com"


(3) RUN命令,指定镜像中运行的命令,包含两种模式。

# shell模式,相当于命令行的/bin/bash -c command
RUN <COMMAND>

# 示例:
RUN echo "hello world"

# exec模式,可以指定其他的shell执行指令
RUN ["executable" "param"...]

# 示例:
RUN ["/bin" "-c" "echo 'hello world'"]

注:如果使用RUN命令切换路径时,先要使用WORKDIR指定工作目录。


(4) EXPOSE命令,用来指定运行该镜像使用的端口,可以指定多个端口,但不一定暴露,在docker run中指定参数-P,不需要指定端口,端口就暴露公开了。

EXPOSE <PORT> [<PORT>...]
# 注:虽然在dockerfile里指定了端口,只是告诉docker里的程序会使用该端口,但在运行时docker并不会自动打开该端口,还是需要指定端口映射,例如docker run -d -P ...


(5) CMD和ENTRYPOINT命令,指定容器运行时的默认行为,和RUN命令类似,RUN命令是在镜像构建时执行,而CMD和ENTRYPOINT命令是在容器启动执行。

CMD和ENTRYPOINT相同点:只能写一条,如果写了多条,那么只有最后一条生效,都是在容器启动时执行。

不同点:使用docker run启动容器指定执行命令,CMD命令会被覆盖(不执行),ENTRYPOINT命令不会被覆盖,如果想要覆盖,在docker run加上参数–entrypoint。

CMD和ENTRYPOINT命令格式:

CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)

ENTRYPOINT ["executable", "param1", "param2"] (exec form, preferred)
ENTRYPOINT command param1 param2 (shell form)

示例:

# 只有CMD命令情况
CMD echo "hello world"

# 只有ENTRYPOINT命令情况
ENTRYPOINT ["echo", "hello world"]

# CMD和ENTRYPOINT都存在情况,CMD作为ENTRYPOINT的参数使用
CMD ["hello world"]
ENTRYPOINT ["echo"]

一般使用entrypoint的中括号形式作为docker 容器启动以后的默认执行命令,里面放的是不变的部分,可变部分比如命令参数可以使用cmd的形式提供默认参数,也就是run里面没有任何参数时使用的默认参数。


(6) COPY和ADD命令,将目录或文件复制镜像中,两者区别是ADD包含了类似tar的解压缩功能,如果只是目录或文件复制,推荐使用COPY。复制目录时需要’/‘结尾,目录不存在会自动创建。

COPY <src> <dest>
ADD <src> <dest>

# src表示来源地址,可以是本地或网络地址,如果是本地地址,必须是镜像的相对地址(dockerfile为参考路劲)。
# dest表示将文件复制到镜像目标地址,必须是绝对路径。

# 示例:
COPY nginx-1.15.2.tag.gz /data/ # 单纯复制文件
ADD nginx-1.15.2.tag.gz /data/  # 解压复制文件夹


(7) VOLUME命令,在镜像中创建挂载点,只要通过该镜像创建的容器都有了挂载点。

VOLUME ["/data1","/data2"]

# 这种方式没有指定宿主机映射,如果使用VOLUME命令构建的新镜像,以该镜像运行2个容器,这两个容器是不能共享数据的,通过执行docker inspect命令得到结果就可以看出映射到宿主机目录完全不一样的,所以两个容器的数据卷不能共享。


(8) WORKDIR命令,指定工作目录,CMD或ENTRYPOINT执行的命令都会在WORKDIR目录下执行。

WORKDIR <PATH>

# 示例:
WORKDIR /a
WORKDIR b
WORKDIR c
# 最后的工作目录是/a/b/c

WORKDIR通常不使用绝对路劲,使用相对路劲可以一直传递下去。


(9) ENV命令,构建镜像过程和容器运行过程都有效。

ENV <KEY> <VALUE>
ENV <KEY>=<VALUE> ...

# 示例:
ENV hw='hello world'


(10) USER命令,容器启动时以什么用户运行,默认使用root用户。

USER user
USER user:gid
USER user:group

USER uid
USER uid:gid
USER uid:group


(11) ONBUILD命令,镜像触发器,当一个镜像被其它镜像作为基础镜像时执行,会在构建过程中插入指令。

ONBUILD <INSTRUCTION>

# 示例:
ONBUILD COPY copyFile/config /data

#在构建基础镜像的dockerfile添加下面命令,实际构建的时候不会执行COPY命令,当构建另一个新镜像并且以该镜像为基础镜像时,会执行COPY命令。


4.8 搭建私有仓库

由于Registry为了安全性考虑,默认是需要https证书支持的,使用ip地址:端口方式来跳过https验证。

# 在一台主机(例如192.168.8.202)上运行一个registry容器,其他能连接这台机器的docker都可以把把镜像push到这个私有仓库里。
docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --restart=always --name=my-registry registry

# 私人仓库没有类似docker hub有界面管理,但是提供web api接口
curl 192.168.8.202:5000/v2/_catalog

# 在另一台主机(例如192.168.8.100)上构建新镜像时,镜像名前缀为192.168.8.202:5000
docker build -t 192.168.8.202:5000/hello-world .

# 把192.168.8.202:5000添加为的docker信任的地址,
vi /etc/docker/daemon.json

    # 添加下面内容,注意:这里填写的是ip,如果填写域名,需要https证书。
        {"insecure-registries":["192.168.8.202:5000"]}

# 重启docker服务
systemctl daemon-reload
systemctl restart docker

# 上传或下载私人仓库的镜像
docker pull busybox

docker tag busybox 192.168.8.202:5000/busybox
docker push 192.168.8.202:5000/busybox
docker pull 192.168.8.202:5000/busybox

# 查看私人仓库
curl http://192.168.8.202:5000/v2/_catalog
curl http://192.168.8.202:5000/v2/busybox/tags/list


4.9 镜像加速

docker拉取镜像时默认指向docker hub的镜像,由于速度比较慢,可以国内的镜像加速器,使用aliyun、daoclound等。

国内常用镜像加速器

地址 说明
https://registry.docker-cn.com docker在国内的加速器,速度也不快
https://zrxnbavs.mirror.aliyuncs.com 阿里云镜像加速器,非常快,建议使用

添加镜像加速器

# 打开docker配置文件
vi /etc/docker/daemon.json
    注:如果重启失败,把daemon.json文件名改为daemon.conf即可。

# 添加镜像加速器地址
{"registry-mirrors": ["https://zrxnbavs.mirror.aliyuncs.com"]}

# 重启docker
systemctl daemon-reload
systemctl restart docker


4.10 导出和导入镜像文件

由于网络原因,镜像下载比较慢,可以在本地已存在的镜像中导出到文件,本地的其他docker可以从本地文件导入。

# 查看镜像
docker images

# 导出镜像,注:导出文件名不要用全路径,需要指定导出tag
docker save -o nats2.0.0.tar.gz docker.io/nats:2.0.0

# 推送镜像文件到其他电脑
scp nats2.0.0.tar.gz root@192.168.3.202:/root/tmp/

# 导入镜像
docker load -i nats2.0.0.tar.gz



5 docker容器网络

4种容器网络类型:

名称 说明
closed container 封闭式的容器,无网络接口,不能外部网络通信的容器,适合无需通信程序运行
bridge container 绑定网桥容器,每个容器都有6种独立的命名空间
join container 联合容器,部分命名空间(USER、MOUNT、PID)是隔离的,而另一部分命名空间(NET、IPC、UTS)是共用的,联合容器使用共同网络,不同容器之间关系类似不同进程的关系
open container 开放式容器,直接共享宿主机网络,也就是说,宿主机能连接的,该容器也能连接。

4种容器网络类型


安装docker成功后,使用ip addr命令查看网络配置情况,会发现多了一个docker0网络,这个docker0其实就是linux的虚拟网桥。

当启动一个容器时,同时容器的命名空间、网络的两端veth,一端在容器中的网路设备上,另一端在docker网桥上。使用命令brctl show查看docker0网桥有哪些容器已经连接上,也可以使用ip link命令查看容器和docker0网桥的桥接情况。

docker网络连接

# 安装查看网桥工具
yum install bridge-utils

# 查看运行的容器
docker ps
    # CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
    # a7a08b417843        busybox             "/bin/bash"           About a minute ago   Up About a minute                       bb01

# 查看网桥
brctl show
    # bridge name     bridge id               STP enabled     interfaces
    # docker0         8000.02421d2f62a1       no              veth5b29135

# 每启动一个容器,虚拟网桥都有一个对应容器的网络接口,也就是容器里的eth0 <----> docker守护进程的veth*

# 使用ip link命令也可看到新启动容器的网络配置
ip link
    # 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    #     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    # 2: eno33554984: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    #     link/ether 00:0c:29:1d:6a:01 brd ff:ff:ff:ff:ff:ff
    # 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    #     link/ether 02:42:1d:2f:62:a1 brd ff:ff:ff:ff:ff:ff
    # 5: veth5b29135@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    #     link/ether da:95:df:07:b9:e7 brd ff:ff:ff:ff:ff:ff link-netnsid 0


5.1 修改docker相关默认网络配置

(1) 修改docker默认的ip地址

vim /etc/docker/daemon.json

# 添加内容:"bip":"10.0.0.1/16"

# 重启docker
systemctl daemon-reload
systemctl restart docker


(2) 连接远程docker服务

docker命令默认是连接本地的docker服务(/var/run/docker.sock),如果想连接远程docker服务,可以配置daemon.json

vim /etc/docker/daemon.json

# 添加内容:"hosts":["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]

# 重启docker
systemctl daemon-reload
systemctl restart docker

# 查看远程docker容器
docker -H 192.168.8.202:2375 ps -a


5.2 容器间使用名称互联

在默认情况系,在同一个宿主机的所有容器都能够互相连接的,docker配置文件OPTIONS的默认参数–icc默认为true,设置为false后禁止其他容器连接。

启动容器时指定该容器代号,可以解决由于重启容器发生ip改变造成连接失效的问题,也就是说,只需要知道容器名称就可以连接到容器了,docker会把容器名字自动映射到ip地址上,类似于域名映射。

需求:以前的做法是当需要连接一个服务时(例如数据库),必须知道数据库ip和端口号才能连接上,但这个服务可能会迁移到其他机器上,此时ip就变更了,在使用原来的ip是无法连接上去的,此时连接端也跟着要变更ip地址,如果服务ip经常变动,造成连接端也经常变更,改来改去比较麻烦。能不能给服务指定一个唯一名称,通过名称就可以连接,不需要知道服务的ip地址,在docker中有多种解决方式。


(1) 使用–link参数指定容器名来连接

在实际中使用–link连接容器情况其实不多,而且只能单方向ping通。

docker run --link=[CONTAINER_NAME]:[ALIAS] [IMAGE] [COMMOND]

# --link表示连接到指定容器,也可以在连接时给一个容器起一个别名,启动后ping 容器名就有可以了,不需要知道该容器ip地址。

# 启动容器bb01
    docker run -it --name bb01 busybox /bin/bash
# 启动容器bb02,并且link到bb01
    docker run --name bb02 --link bb01 -it busybox /bin/bash

# 在容器bb02中使用命令ping bb01,可以ping通,但在容器bb01中,使用命令ping bb02是失败的,只能ping 容器bb02的ip才可以ping通,在两个容器中输入env命令,发现容器bb02的环境变量有BB01_NAME=/bb02/bb01,而容器bb01是没有的。也就是启动容器bb02中,在link的时候也添加了环境变量。

注:当重启docker守护进程后,注意启动顺序,先启动link容器(bb01),然后在启动其他容器。


(2) 通过新建网桥连接不同网段的容器

查看docker网络

docker network ls

发现有三个网络:

  • bridge,这是docker0网桥,容器启动时默认连接到docker0。
  • host,这是宿主机网络,容器启动时指定host网络,容器ip和host公用主机网络ip和端口,注意使用中端口冲突问题。
  • none,这是空网络,没有ip地址,要访问容器,只能使用命令docker exec进去访问。
# 先启动两个容器bb01、bb02,这两个容器默认是连接到docker0网桥上的
docker run -it --name bb01 busybox /bin/bash
docker run -it --name bb02 busybox /bin/bash

# 在docker上创建一个新的网桥br01
docker network create -d bridge br01
  
# 查看docker网络列表,是否存在新建网桥br01
 docker network ls
    # NETWORK ID          NAME                DRIVER              SCOPE
    # e5e68cb12654        br01                bridge              local
    # ee4eb19a12c8        bridge              bridge              local
    # 32534b5daf5e        host                host                local
    # 16e2df8241ac        none                null                local


# 查看网桥列表,是否多了一个新建的网桥
 brctl show
    # bridge name     bridge id               STP enabled     interfaces
    # br-e5e68cb12654         8000.0242f1ac5b5d       no
    # docker0         8000.02421d2f62a1       no

# 启动一个容器bb03,指定网络为新建的网桥br01。
docker run --name bb03 --network br01 -it busybox /bin/bash


# 查看此时网桥详情信息
docker network inspect br01

# 此时网桥下有一个容器bb03,ip地址为173.18.0.2,明显和容器bb01、bb02在不同的网段,也无法通信的。

# 把bb01和bb02连接到新建的网桥br01上
docker network connect br01 bb01
docker network connect br01 bb02

# 在容器bb01中执行ping命令
ping bb03
ping bb02

# 在容器bb02中执行ping命令
ping bb01
ping bb03

# 在容器bb03中执行ping命令
ping bb01
ping bb02

# 发现都能通过名字ping通的,通过docker新建的网桥,通过docker network connect另一网桥下的容器之后,使得docker不同网桥下的容器可以相互使用容器名字来连接,不再需要ip地址。
  
# 使用命令ip adddr查看容器bb01、bb02此时的网络,发现多了一个br01网桥的连接的
# 使用命令docker network inspect br01 br01查看网桥详情信息时,发现也多了容器bb01和bb02。


允许特定容器的连接:

# 清空宿主机的iptables
 iptables -F

# 查看宿主机的iptables
 iptables -L -n

# 设置docker配置选项OPTIONS的--icc为false,重启docker守护进程

# 启动容器是使用--link参数


5.3 使用etcd实现容器间跨主机通信

实现容器间跨主机通信可以使用net(要经过两次转换,效率低下,容器之间不可见)或overlay(常用)。

下图中的两个不同主机中容器是怎么通信的?

首先要保证两个容器的ip地址不一样,而且两个主机能互相通信的,原理是把容器的发出去的包封装在底层网络上面,在另外一端同样的原理依次解包。

容器间跨主机通信


VXLAN(Virtual Extensible LAN)是一种网络虚似化技术,试图改进大型云计算的部署时的扩展问题,可以说是对vlan的一种扩展。

vxlan完整数据包

vxlan完整数据包


实现容器间通信方法

# 准备两个装有docker的虚拟机,虚拟机1的ip地址为192.168.8.200,节点名称为docker-node1;虚拟机2的ip地址为192.168.8.202,节点名称为docker-node2

# 在虚拟机1和虚拟机2分别安装分布式KV存储工具etcd
cd /usr/local/src

# 下载
wget https://github.com/etcd-io/etcd/releases/download/v3.3.9/etcd-v3.3.9-linux-amd64.tar.gz

# 解压和改名
tar zxvf etcd-v3.3.9-linux-amd64.tar.gz
mv etcd-v3.3.9-linux-amd64 etcd
mv etcd /usr/local/

# 添加到环境变量
vim ~/.bash_profile
    # 把/usr/local/etcd追加到PATH后面
source ~/.bash_profile

# 在虚拟机1启动etcd
nohup etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.8.200:2380 \
--listen-peer-urls http://192.168.8.200:2380 \
--listen-client-urls http://192.168.8.200:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.8.200:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.8.200:2380,docker-node2=http://192.168.8.202:2380 \
--initial-cluster-state new &


# 在虚拟机2启动etcd
nohup etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.8.202:2380 \
--listen-peer-urls http://192.168.8.202:2380 \
--listen-client-urls http://192.168.8.202:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.8.202:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.8.200:2380,docker-node2=http://192.168.8.202:2380 \
--initial-cluster-state new &

# 在两个虚拟机上都可以查看集群etcd健康状态
etcdctl cluster-health

# 修改虚拟机1的docker配置文件
vim /etc/sysconfig/docker
    # 把下面两个启动参数添加到OPTIONS里面
    --cluster-store=etcd://192.168.8.200:2379 --cluster-advertise=192.168.8.200:2375

    # 重启docker服务
    systemctl restart docker

# 修改虚拟机2的docker配置文件
vim /etc/sysconfig/docker
    # 把下面两个启动参数添加到OPTIONS里面
    --cluster-store=etcd://192.168.8.202:2379 --cluster-advertise=192.168.8.202:2375

    # 重启docker服务
    systemctl restart docker

# 在虚拟机1的docker上创建一个新的overlay类型的网络,不需要在虚拟机2的docker创建
docker network create -d overlay ol_demo

    # 查看虚拟机2的docker是否也有名称为ol_demo的网络
    docker network ls
    # 如果有,则说明网络同步成功了。

    # 在etcd中查看docker网络或节点信息
    # 查看网络信息
    etcdctl ls /docker/network/v1.0/network

    # 查看节点信息
    etcdctl ls /docker/nodes

    # 在docker中查看新建网络test_etcd信息
    docker network inspect test_etcd

# 在虚拟机1的docker启动一个容器bb01
docker run --name bb01 --network ol_demo -it busybox /bin/bash

# 在虚拟机2的docker启动一个容器bb02
docker run --name bb02 --network ol_demo -it busybox /bin/bash

# 检验两个容器是否能相互ping通
    # 在容器bb01上
    ping bb02

    # 在容器bb02上
    ping bb01

    # 能够相互ping通说明容器间跨主机通信成功。

# 查看此时的网络ol_demo详情信息,包含两个容器bb01,bb02
docker network inspect ol_demo


5.4 使用swarm网络实现容器间跨主机通信

docker swarm实现去中心化管理集群,集群有多个worker节点和manager节点组成,为了避免manager单点的问题,swarm集群也支持多个manager,但管理worker时只有一个manager有效。

现在有4个虚拟机m1、m2、w1、w2,创建集群目标有两个manager节点,2个worker节点。

# 首先在虚拟机m1初始化swarm集群
docker swarm init
    # 创建集群是也可以添加参数:
    --listen-add ip:port  # 指定管理者节点ip地址和端口
    --advertise-addr ip:port  # 广播地址

# 在虚拟机m1执行生成manager节点加入的token
docker swarm join-token manager
# 复制新生成的join-token到虚拟机m2执行,则虚拟机m2也成为了swarm集群的manager节点,也就是说虚拟机m1和m2都是manager节点。

# 在虚拟机m1执行生成worker节点加入的token
docker swarm join-token worker
# 复制新生成的join-token到虚拟机w1和w2的终端上执行,虚拟机w1和w2加入到swarm集群。

# 查看集群的节点,只能在manager节点上运行
docker node ls

# 查看swarm集群网络,有一个overlayl类型的网络,这个网络只是用来管理集群节点的,并不是用来做业务通信,如果要做业务通信需要新建一个overlay类型网络
docker network ls

# 创建overlay网络,这个网络实现跨主机容器间通信
docker network create -d overlay --attachable bb-net
# 其他虚拟机的docker网络也会自动新添加overlay网络bb-net

# 在虚拟机m1上创建容器bb01
docker run --name bb01 --network bb-net -it busybox /bin/bash

# 在虚拟机m2上创建容器bb02
docker run --name bb02 --network bb-net -it busybox /bin/bash

# 在虚拟机w1上创建容器bb03
docker run --name bb03 --network bb-net -it busybox /bin/bash

# 在虚拟机w2上创建容器bb04
docker run --name bb04 --network bb-net -it busybox /bin/bash

# 测试是否能够ping通
    # 进入在虚拟机m1容器bb01里
    ping bb02
    ping bb03
    ping bb04

    # 进入在虚拟机m2容器bb02里
    ping bb01
    ping bb03
    ping bb04

    # 进入在虚拟机w1容器bb03里
    ping bb01
    ping bb02
    ping bb04

    # 进入在虚拟机w2容器bb04里
    ping bb01
    ping bb02
    ping bb03

# 如果都能ping通,说明使用swarm集群的网络实现跨主机通信。



6 容器的数据管理

docker主要将应用与其相关的环境镜像打包,通常docker的生存周期和应用程序声明周期是一致的,但是对数据的要求是持久的,并且docker之间也需要有一个共享数据的渠道,这些需求就催生了docker数据卷的产生。

什么是docker数据卷?

数据卷是经过特殊设计的目录,可以绕过联合文件系统(UFS),为一个或多个容器访问。

docker数据卷产生原因?

数据卷设计的目的是在于数据的永久化,它完全独立与容器的生存周期,因此,docker不会在容器删除时删除其挂载的数据卷,也不会存在类似的垃圾收集机制,对容器引用的数据卷进行处理。

docker的数据卷

docker数据卷特点:

  • 数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,这些数据会拷贝到新初始化的数据卷中。
  • 数据卷可以在容器之间共享和重用。
  • 可以对数据卷里的内容直接进行修改。
  • 数据卷的变化不会影响镜像的更新。
  • 数据卷会一直存在,即使挂载数据卷的容器已经被删除。


6.1 存储卷类型

(1) 绑定挂载卷

绑定挂载卷需要明确指定宿主机路径和容器的路径。

docker run -v <src>:<dest>:[permission] [-it] 镜像名

# -v表示启动容器时添加数据卷,src是宿主机的目录,dest是容器里的目录,如果src或dest都不存在,docker会自动创建。
# permission表示容器里文件夹权限,rw(读写,默认)、ro(只读)、wo(只写)。

# 示例:
docker run -v ~/vdata:/data/ --name mc02 -it vison/centos02 

# 在容器里写入数据
echo 'hello world' >> /data/test

# 在宿主机上查看数据
cat ~/vdata/test

# 通过docker inspect mc02命令可以查看容器数据卷路径和权限
"Mounts": [
    {
        "Type": "bind",
        "Source": "/home/vison/vdata",
        "Destination": "/data",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
]


(2) docker管理卷

docker管理卷不需要指定宿主机路径,由docker自动映射到宿主机。

docker run -it --rm --name bb01 -v /data busybox

# 通过docker inspect bb01查看Mounts挂载在宿主机路径


6.2 数据卷容器

什么是数据卷容器?

命名的容器挂载数据卷,其他容器通过挂载这个容器实现数据共享,这个挂载数据卷的容器就叫做数据卷容器。

数据卷容器


挂载数据卷容器的方法:

docker run --volumes-from [CONTAINER NAME]

# --volumes-from表示挂载数据卷容器。

# 例如构建一个新镜像,Dockerfile中有个添加容器数据卷命令VOLUME ["/data"]
docker build -t vison/centos02 ./test

# 首先以镜像vison/centos02启动一个容器mc02
docker run --name mc02 -it vison/centos02

# 在容器mc02里添加数据到/data/test
echo 'mc02' >> /data/test

# 以镜像vison/centos02又启动一个新容器mc03
docker run --volumes-from mc02 -it --name mc03 vison/centos02

# 在容器mc03里添加数据到/data/test
echo 'mc03' >> /data/test

# 在容器里通过命令cat /data/test都可以看到写入的数据,两个容器间可以共享数据

注:这种共享数据好处是,容器之间不需要知道映射宿主机的路径。即使删除了数据卷容器(mc02),不影响另一个容器(mc03)读写共享的数据。


6.3 docker数据备份和还原

docker数据备份和还原


数据备份方法:

docker run --volumes-from <CONTAINER> -v src:dest <IMAGE> tar cvf <file.tar> <container data volume>

# 备份时使用到数据卷容器、容器的数据卷和压缩命令。

# 示例:
docker run --volumes-from mc02 -v ~/backup:/backup -it --name mc04 vison/centos02 tar cvf /backup/data.tar /data1


数据还原方法(备份的逆操作):

docker run --volumes-from <CONTAINER> -v src:dest <IMAGE> tar xvf <file.tar> <container data volume>


# 示例:
# 新启动一个全新容器
docker run -it --name mc05 vison/centos02

# 在新的容器上还原数据
docker run --volumes-from mc05 -v ~/backup:/backup vison/centos02 tar xvf /backup/data.tar



7 容器管理工具docker-compose

docker-compose官方文档:https://docs.docker.com/compose/

docker-compose产生原因:如果一个完整项目有多个容器组成,这时只能一个一个管理,比较麻烦,为了能够批处理这些容器,减少繁琐的操作,于是就有了docker-compose。

docker-compose特点:

  • docker-compose是一个命令行工具。
  • 这个工具可以通过一个yaml文件定义多容器的 docker应用。
  • 通过一条命令就可以根据yaml文件的定义去创建或者管理多个容器。


7.1 安装docker-compose

# 下载Docker-Compose二进制文件
curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

# 改为可执行文件
chmod +x /usr/local/bin/docker-compose

# 安装docker-compose自动补全脚本
curl -L https://raw.githubusercontent.com/docker/compose/1.25.0/contrib/completion/bash/docker-compose -o /usr/share/bash-completion/completions/docker-compose

# 刷新
source /usr/share/bash-completion/completions/docker-compose


7.2 docker-compose配置文件解析

docker-compose默认配置文件名为docker-compose.yml,它由三大部分组成。

docker-compose组成

一个servicer代表一个容器,这个容器可以是dockerhub的 镜像,或者在本地docker build dockerfile出来的镜像。

Service的启动类似docker run,我们可以给其指定network和volume,所以可以给 service指定networki和Volumer的引用


docker-compose配置文件详解:


# (1) service模块
services:
  # 服务名称
  web:

    # 容器名称
    container_name: my-app

    # 服务镜像
    image: app:1.15

    # 重启策略
    restart: always

    # 执行命令或参数,类似docker run 的运行命令,可以覆盖容器启动后默认执行的命令
    command: app --configFile config/config.toml

    # 容器的依赖,启动先后的问题
    depends_on:
      - db
      - redis

    # 关联的容器,对应docker run的link参数
    links:
      - mysql

    # 映射端口,使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口。
    ports:
      - "6000"
      - "8080:8080"
      - "127.0.0.1:9000:9000"

    # 暴露端口,只是会向链接的服务(linked service)提供,只有内部端口可以被指定,通常和links配合使用
    expose:
      - "3000"  
      - "8000"  

    # 挂载一个目录或者一个已存在的数据卷容器
    volumes:
      # 使用绝对路径挂载数据卷
      - /opt/data:/var/lib/mysql
      # 使用以Compose配置文件为中心的相对路径挂载数据卷
      - ./cache:/tmp/cache
      # 使用用户的相对路径(~/ 表示的目录是/home/<用户目录>/ 或者 /root/)
      - ~/configs:/etc/configs/:ro
      # 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)
      - /var/lib/mysql
      # 已经存在的命名的数据卷。
      - datavolume:/var/lib/mysql

    # 传递到容器作为环境变量
    environment:
      - DEFAULT_USER: guest
      - DEFAULT_PASS: guest

    # dns解析地址
    dns:
      - 114.114.114.114
      - 8.8.8.8

    # 让Compose项目里面的容器连接到那些项目配置外部的容器,前提是外部容器中必须至少有一个容器是连接到与项目内的服务的同一个网络里面
    external_links:
      - redis_1

    # 往/etc/hosts文件中添加一些记录,从而添加主机映射
    extra_hosts:
      - "somehost:162.242.195.82"

    # 程序入口
    entrypoint: /usr/local/bin/cluster-entrypoint.sh

    # 从其它容器或者服务挂载数据卷
    volumes_from:
      - service_name

    # 可以指定使用服务或者容器的网络
    network_mode:

# 还有其他参数working_dir entrypoint user hostname domainname mem_limit privileged restart stdin_open tty cpu_shares等


(2) volumes模块
volumes:
  # db-data是变量,它的值在volumes模块定义
  db-data:
    - /data/mysql



(3) networks模块
networks:
  # back-tier它的值在networks模块定义,如果不指定driver,默认使用docker0
  back-tier:
    driver:bridge


一个完整的docker-compose.yml例子如下:

version: '3'

services:

  wordpress:
    image: wordpress
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_PASSWORD: root
    networks:
      - my-bridge

  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - my-bridge

volumes:
  mysql-data:

networks:
  my-bridge:
    driver: bridge


7.3 docker-compose命令使用

(1) 启动容器

docker-compose up [OPTIONS]

# -d表示守护进程方式运行;-f表示指定配置文件,默认值为docker-compose.yml

# 示例:
docker-compose up -d


(2) 停止容器

docker-compose [stop | down]

# stop表示只停止容器;down表示停止并删除容器、网络、数据卷。

# 示例:
docker-compose stop


(3) 重新启动容器

docker-compose start

# 示例:
docker-compose start


(4) 在容器中启动新进程

docker-compose exec <CONTAINER> <COMMAND>

# 示例:
docker-compose exec mysql bash


(5) 查看运行的容器列表

docker-compose ps


(6) 编译容器

# 如果有更改程序代码,需要先执行
docker-compose build

# 然后启动容器
docker-compose up -d


(7) 自定义启动容器服务数量

docker-compose up --scale <容器名>=<数量> -d

示例:
docker-compose up --scale web=5 -d


7.4 在同一台宿主上实现负载均衡服务

当一个服务访问量超过单个服务能力时,需要横向扩展多个服务,访问请求在经过负载均衡分散访问到各个服务上,这种横向扩展服务方式可以很方便提高服务能力,而且扩展能力弹性的,可增大可缩小,如下图所示:

负载均衡

下面是实现负载均衡的一个示例,一共有三个容器,分别是redis、web、haproxy(负载均衡),通过部署多个web容器横向扩展web服务,通过负载均衡haproxy把请求分散多个web服务,docker配置文件如下:

(1) Dockerfile文件内容

FROM python:2.7
LABEL maintaner="Peng Xiao xiaoquwl@gmail.com"
COPY . /app
WORKDIR /app
RUN pip install flask redis
EXPOSE 80
CMD [ "python", "app.py" ]


(2) app.py文件内容

from flask import Flask
from redis import Redis
import os
import socket

app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello Container World! I have been seen %s times and my hostname is %s.\n' % (redis.get('hits'),socket.gethostname())


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80, debug=True)


(3) docker-compose.yml文件内容

version: "3"

services:

  redis:
    image: redis

  web:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      REDIS_HOST: redis

  haproxy:
    image: dockercloud/haproxy
    links:
      - web
    ports:
      - 8080:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock 


如果启动时不指定–scale参数时,默认只启动配置文件里服务各一个。

docker-compose up -d

横向扩展web服务数量
docker-compose up web=5 -d

也可以横向缩小web服务数量
docker-compose up web=2 -d

查看是否启动多个web服务
docker-compose ps

检验是否使用了负载均衡,执行多次查看是否返回不同容器id。

curl 127.0.0.1:8080



8 容器监控

安装一个开源软工具scope

# 下载scope
curl -L git.io/scope -o /usr/local/bin/scope

# 改为可执行
chmod a+x /usr/local/bin/scope

# 启动监控,在docker中启动一个名为weavescope容器
scope launch

    # 启动容器成功后提示访问地址,在浏览器上可以查看容器监控图表
    # Weave Scope is listening at the following URL(s):
    # * http://192.168.8.200:4040/
    # * http://192.168.8.102:4040/

# 停止监控
scope stop

score监控界面


可以同时监控多台主机容器,在每台主机上都运行相同的命令

scope launch 192.168.8.200 192.168.8.202

点击界面菜单栏Hosts上会显示监控的主机



专题「工具」的其它文章 »