docker介绍

一、为什么需要Docker

官方介绍(中文版):http://www.docker-cn.com/what-docker#/developers

Docker 是世界领先的软件容器平台。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用 Docker 可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用 Docker 可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为 Linux 和 Windows Server 应用发布新功能。
1.1环境(切换/配置)麻烦一般我们写程序的,能接触到好几个环境:

  • 自己写代码的环境叫做开发环境。
  • 给测试去跑的环境叫做测试环境。
  • 测试完可以对外使用的叫做生产环境。

其实我们在学习编程中,很多时间都浪费在“环境”上:

  • 如果我现在重装了系统,我想要跑我的war/jar包,我得去安装一下JDK、Tomcat、MySQL等配置各种的环境变量才能跑起来。
  • 开开心心地跟着博主给出的步骤去写Demo,但总是有Bug。(这里我将版本/依赖也归纳在环境的范畴里边)。
  • 好不容易在测试环境下跑起来了,在生产环境就各种出错!
  • 跟着教学视频做分布式/集群的项目,跑一堆的虚拟机,每个虚拟机都要安装对应的环境。

所以就有个笑话《千万不要跟程序员说,你的代码有bug》:

  • 他的第一反应是你的环境有问题,第二就是你是傻逼不会用吧。
  • 你要跟他这么说:“这个程序运行的怎么运行的跟预期不一样,是我操作有问题吗?”。
  • 这货就会第一反应“我擦,这是不是出bug了?”

1.2应用之间需要隔离比如我写了两个应用(网站),这两个应用部署在同一台服务器上,那可能会出现什么问题?

  • 如果一个应用出现了问题,导致CPU占100%。那另一个应用也会受到关联,跟着一起凉凉了。
  • 这两个应用是完全不同技术栈的应用,比如一个PHP,一个.NET。这两个应用各种的依赖软件都安装在同一个服务器上,可能就会造成各种冲突/无法兼容,这可能调试就非常麻烦了。

二、Docker是如何解决上述的问题的

2.1解决环境(切换/配置)

不知道大家有没有装过系统,比如说装Linux虚拟机,重装Windows系统,都是需要镜像的。有了这个镜像,我们就可以运行这个镜像,来进行安装系统的操作(此处省略N个下一步),于是我们的系统就装好了。一般来说,我们去官方渠道下载的镜像,都是纯净的。比如去官方下载Windows镜像,装完后之后桌面只有一个回收站。但有过了解装系统的同学可能就会知道,有的镜像装完可能还有360这些软件,但系统的的确确是变了。简单来说,就是这些镜像添加了其他的东西(比如360软件、腾讯、千千静听等等软件)。Docker也是这种思路,可以将我们的想要的环境构建(打包)成一个镜像,然后我们可以推送(发布)到网上去。想要用这个环 境的时候,在网上拉取一份就好了。有了Docker,我们在搭环境的时候,跟以前的方式就不一样了。

  • 之前:在开发环境构建出了一个war包,想跑到Linux下运行。我们得先在Linux下载好Java、Tomcat、MySQL,配置好对应的环境变量,将war包丢到Tomcat的webapps文件夹下,才能跑起来。
  • 现在:在Linux下直接拉取一份镜像(各种环境都配好了),将镜像运行起来,把war包丢进去就好了。

将Docker的镜像运行起来就是一两秒的事情而已,十分方便的。

2.2解决应用之间隔离

说到这里,就得提出一个大家可能不认识的概念:LXC(Linux Containers)--->Linux容器。Linux容器在Linux内核中,提供了cgroups功能,来达成资源的区隔化。它同时也提供了名称空间(namespace)区隔化的功能,使应用程序看到的操作系统环境被区隔成独立区间,包括进程树,网络,用户id,以及挂载的文件系统。简单来说就是:LXC是一个为Linux内核包含特征的用户接口。通过强大的API和简单的工具,它可以让Linux用户轻松的创建和托管系统或者应用程序容器。回到Docker我们在翻看Docker的官方文档的时候,也很容易看见cgroup和namespace这两个名词:来源维基百科:Early versions of Docker used LXC as the container execution driver, though LXC was made optional in v0.9 and support was dropped in Docker v1.10.

lxc是早期版本docker的一个基础组件,docker 主要用到了它对 Cgroup 和 Namespace 两个内核特性的控制。新的Docker版本已经移除了对LXC的support。Docker在Windows和Mac上面说了,Docker底层用的Linux的cgroup和namespace这两项技术来实现应用隔离,那Windows和Mac用户能用Docker吗?

  • 之前,Windows和Mac使用Docker实际上就是跑了一层Linux虚拟机。 比如在Windows下安装的是Docker Toolbox,它需要Oracle Virtual Box来跑Docker
  • 现在,Windows和Mac都已经原生支持Docker了。但需要一些安装的条件,详情可以查看官网,比如Windows:Docker for Windows requires 64bit Windows 10 Pro and Microsoft Hyper-V

参考资料:Windows 原生 Docker 正式商用 http://blog.daocloud.io/windows-docker/

三、虚拟机和Docker

说到应用隔离和镜像,我就想起了虚拟机。今年下半年(此处省略.....),文体两开花(此处省略.....),要是我写文章写得不好,我是需要向XX谢罪的。估计大家都用过虚拟机,虚拟机也能实现对应用的隔离,安装特定的镜像也能跑出我们想要的环境。虚拟机已经发展了很久了,为什么我们还需要Docker呢?这部分内容在官网也有相关的介绍: http://www.docker-cn.com/what-container#/virtual_machines

一句话总结:Docker容器比虚拟机轻量多了!最后Docker可以干嘛?

  • 将一整套环境打包封装成镜像,无需重复配置环境,解决环境带来的种种问题。
  • Docker容器间是进程隔离的,谁也不会影响谁。

来自https://zhuanlan.zhihu.com/p/54512286

docker 使用

docker命令:

命令    说明

run    创建一个新容器并运行

start    开启一个容器并使其在后台运行

stop    停止一个容器

restart    重启一个容器

kill    杀掉一个容器进程

rm    删除容器

pause    暂停容器

unpause    恢复暂停容器

create    从镜像中创建一个容器

exec    对一个容器执行shell命令

ps    列出容器

inspect    获取容器或镜像的元数据

top    查看正在运行中的容器进程信息

attach    链接正在运行的容器

events    从docker服务器获取事件logs    获取docker日志

wait    让一个容器进入等待使其进入阻塞状态

export    将一个容器的文件系统打包至tar

port    列出一个容器的端口映射情况

container    管理已经运行的容器的

deploy    部署新的堆栈或更新已有堆栈的

update    更新容器

rename    重命名容器

volume    卷管理

commit    提交一个容器的文件系统使之生成一个新的镜像

cp    向一个正在运行的容器复制文件或将容器中的文件复制出来

diff    检查一个容器文件系统更改情况

login    docker登入

logout    docker登出

pull    拉取镜像

push    推送镜像至服务器

search    在docker hub上查询镜像

images    列出镜像

rmi    删除镜像

tag    修改本地某一镜像的标记使其镜像属于某一仓库

build    通过指定Dockerfile文件编译镜像

history    查看镜像历史

save    将制定镜像保存成tar文件

load    从tar中恢复镜像

import    从tar中创建一个新镜像

checkpoint    设置checkpoint类似于恢复点可以让镜像撤销到曾经设置的某一个checkpoint上

image    docker镜像管理

manifest    docker镜像清单管理

trust    docker可信镜像管理

swarm    docker集群管理工具

node    docker集群节点控制

stack    docker集群堆栈管理

info    查询docker信息

version    查询docker版本

system    docker系统管理

stats    docker容器资源使用统计

config    管理docker配置

network    docker网络管理

plugin    docker插件管理

secret    docker敏感信息管理

service    docker服务管理

docker安装

Ubuntu下安装

`sudo apt install docker.io

sudo usermod -aG docker $USER 将账户添加进docker后重新登录账户才可使用docker命令

Centos安装

卸载原有的 docker

sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate 

清理残留目录

sudo rm -rf /var/lib/dockersudo rm -rf /var/run/docker

  • 安装 yum-utils,它提供了 yum-config-manager,可用来管理yum源

sudo yum install -y yum-utils

  • 添加yum源

sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

  • 更新yum索引

sudo yum makecache fast

  • 安装 docker-ce

sudo yum install -y docker-ce

  • 设置为系统服务

sudo systemctl enable docker

设置镜像仓库源默认的镜像仓库是国外的,拉取镜像的速度很慢,所以为了方便镜像获取,可以更改镜像源,方法是添加一个配置文件

sudo vi /etc/docker/daemon.json

添加的信息如下:{"registry-mirrors": ["https://registry.docker-cn.com"]}添加完命令之后,需要重启一下容器服务:

sudo systemctl daemon-reloadsudo systemctl restart docker

现在执行一下 info 命令,可以查看到 docker 的镜像源已经更改为国内的了,下面就可以拉取镜像了,可以先docker search一下一般官方镜像都是原名,一般都有alpine版的小一点的(alpine是非常小的linux操作系统)目前也有很多人在用。

docker pull mysql

拉下来之后docker image就可以看到了

docker run -id -p 3306:3306 mysql -e MYSQL_ROOT_PASSWORD=123456

-d是后台运行-i可交互,-p 指定宿主3306端口映射容器中的3306端口,也可以用-v 命令映射本地文件夹和容器内的文件夹,上面这句如果本地mysql,会直接区docker上拉取latest版本运行运行后会有一个容器id

3abeb8b3c0638d3a447375acfe01834a829ee69c10416e729f578dc4befa8a7d

docker exec -it  3ab bash

可以进去mysql的虚拟主机里操作了,直接取容器id的前几位就行如果对运行的这个镜像做了更改想要保存:docker commit mysql:自己定义的版本号

后面也可加其他参数比如作者,或备注啥的也可以把镜像保存到本地文件

docker save -o mysql_v3.tar mysql:v3

也可以导入tar镜像

docker import mysql_v3.tar mysql:v3

还可以把镜像存储到docker上,这个要有docker的账号,docker login后然后把你要推的镜像名前面加上你docker的id:

docker push yourid/mysql:v3

docker run后面也可以加其他很多参数

  • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
  • -d: 后台运行容器,并返回容器ID;
  • -i: 以交互模式运行容器,通常与 -t 同时使用;
  • -P: 随机端口映射,容器内部端口随机映射到主机的高端口
  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
  • --name="nginx-lb": 为容器指定一个名称;
  • --dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
  • --dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
  • -h "mars": 指定容器的hostname;
  • -e username="ritchie": 设置环境变量;
  • --env-file=[]: 从指定文件读入环境变量;
  • --cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
  • -m :设置容器使用内存最大值;
  • --net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
  • --link=[]: 添加链接到另一个容器;
  • --expose=[]: 开放一个端口或一组端口;
  • --volume , -v: 绑定一个卷

Dockerfile

docker还有一个常用的功能,可以使用Dockerfile文件来自动的生成镜像,可以根据需要添加或更改配置,我们可以根据项目需要,来定制镜像,比如定制一个基于Ubuntu18.04的镜像,装有nginx,python3,redis,镜像里的操作都是基于root用户,安装包的话可以wget获取也可以自己准备好,我是准备好了。具体参数及介绍如下:

FROM ubuntu:18.04
MAINTAINER nix
ARG pip_url=https://pypi.tuna.tsinghua.edu.cn/simple
ARG pip_host=https://pypi.tuna.tsinghua.edu.cn
# 1.准备工作创建文件夹
RUN \    
    mkdir -p /project/packages \    
    && mkdir -p /project/logs \    
    && mkdir -p ~/.pip \
# 复制配置文件
COPY packages/web /project/
COPY confs /project/
COPY confs/pip.conf /root/.pip
COPY confs/sources.list /etc/apt/sources.list
# 复制安装包
COPY packages /project/
# 配置python
RUN \    
    apt -y install make g++ gcc  zlib1g-dev libffi-dev libc6-dev tk-dev tcl python3-pip python-setuptools vim libmysqlclient-dev libssl-dev -y \    
    && cd /project/packages \    
    && tar -xzf Python-3.8.1.tgz \    
    && cd Python-3.8.1 \    
    && ./configure --enable-optimizations \    
    && make && make install \    
    && cd /project/confs \    
    && python3 -m pip install -r requirements.txt -i ${pip_url} --trusted-host ${pip_host} \    
    && rm -rf /var/cache/apt/*
# 安装redis
RUN \    
    cd /project/packages \    
    && tar -xzf redis-5.0.7.tar.gz \    
    && cd redis-5.0.7 \    
    && make && make install \    
    && rm -rf /var/cache/apt/*
    # 安装 nginx
RUN \    
    apt install libpcre3 libpcre3-dev -y \    
    && cd /project/packages \    
    && tar -zxv -f nginx-1.16.1.tar.gz \    
    && cd nginx-1.16.1 \    
    && ./configure --with-http_stub_status_module \    
    && make && make install \    
    && rm -rf /var/cache/apt/*
# 设置环境变量
EXPOSE 80 3306 6379
CMD /usr/local/bin/supervisord -c /project/confs/supervisord.conf

指令详解

FROM:定制的镜像都是基于 FROM 的镜像,这里的 ubuntu:18.04就是定制需要的基础镜像。后续的操作都是基于 ubuntu:18.04。

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

shell 格式:

RUN <命令行命令># <命令行命令> 等同于在终端操作的 shell 命令,比如上面的。

exec 格式:

RUN ["可执行文件", "参数1", "参数2"]# 例如:

RUN ["./python.py", "arg1", "arg2"] 等价于 RUN ./python.py arg1 arg2

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

FROM ubuntu:18.04
RUN apt install wget -y
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.7.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM ubuntu:18.04
RUN apt install wget -y \   
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.7.tar.gz" \    
    && tar -xvf redis.tar.gz

如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

COPY复制指令,从上下文目录中复制文件或者目录到容器里指定路径。格式:

COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

[--chown=:] 可选参数,用户改变复制到容器内文件的拥有者和属组。<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY confs* /insidedir/

COPY confs?.txt /insidedir/

<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。

ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

CMD 在docker run 时运行。RUN 是在 docker build。作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。格式:

CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。示例:假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参

1、不传参运行

$ docker run nginx:test

容器内会默认运行以下命令,启动主进程。nginx -c /etc/nginx/nginx.conf

2、传参运行

$ docker run nginx:test -c /etc/nginx/new.conf

容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf

ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。格式:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下示例设置 NGINX_VERSION = 1.16.1, 在后续的指令中可以通过 $NGINX_VERSION 引用:

ENV NGINX_VERSION 1.16.1

RUN wget -P /project/packages http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz

ARG构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。格式:

ARG <参数名>[=<默认值>]

VOLUME定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。作用:避免重要的数据,因容器重启而丢失,这是非常致命的。避免容器不断变大。格式:

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE仅仅只是声明端口。作用:帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。格式:

EXPOSE <端口1> [<端口2>...]

WORKDIR指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。格式:

WORKDIR <工作目录路径>

USER用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。格式:

USER <用户名>[:<用户组>]

HEALTHCHECK用于指定某个程序或者指令来监控 docker 容器服务的运行状态。格式:

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

ONBUILD用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。格式:ONBUILD <其它指令>

构建镜像

构建时我们切换到Dockerfile所在目录,然后

$ docker build -t myubuntu:1.0 .

开始构建

nix@ubuntu:~/docker/build$ docker build -t myubuntu:1.0 .

Sending build context to Docker daemon  283.1MB
Step 1/20 : FROM ubuntu:18.04

---> ccc6e87d482b
Step 2/20 : MAINTAINER nix

---> Using cache

---> 9f7ec61970ab
Step 3/20 : ARG pip_url=https://pypi.tuna.tsinghua.edu.cn/simple

---> Using cache

---> bfb080662934
Step 4/20 : ARG pip_host=https://pypi.tuna.tsinghua.edu.cn

---> Using cache

---> 5626ebe7ba9e
Step 5/20 : RUN     mkdir -p /project/packages   && mkdir /project/logs     && mkdir -p ~/.pip

---> Running in 21d8c4ab2779Removing intermediate container 21d8c4ab2779

---> aa636df29ba4
Step 6/20 : ADD packages/web /project/

---> fdf1b98e04cc
Step 7/20 : COPY confs/sources.list /etc/apt/sources.list

---> defa9cc391ae
Step 8/20 : COPY confs/pip.conf /root/.pip

...........

完成后,docker images就可以看到新build的镜像了。如果你要装的软件很多,整个过程会有点慢,而且镜像还会很大,上面这个就快要2g,我试过build整个项目在一个镜像里,最后差不多3g大小,试过python3和依赖库也有1.3g……所以大家可以使用alpine版的,或者组合使用。

命令最后一个 . 是上下文路径,那么什么是上下文路径呢?

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

镜像组合使用

本站点需要nginx,redis,python3,mysql,我们首先pull拉取官方镜像,我们可以使用sh脚本的方式启动多容器,但官方还有一个更方便的工具,docker-compose。

docker-compose通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。

安装:

pip install docker-compose

docker-compose也有一个跟Dockerfile类似功能的配置文件,docker-compose.yml

配置如下:

version: "6"
services:

  db:
    restart: always
    image: ${MYSQL_IMAGE}
    container_name: web_db
    volumes:
      - ./db/mysql:/var/lib/mysql
      - ./confs/my.cnf:/etc/my.cnf:ro
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_NAME}
    networks:
      - backend

  redis:
    restart: always
    image: ${REDIS_IMAGE}
    container_name: web_redis
    networks:
      - backend

  web:
    restart: always
    image: ${WEB_IMAGE}
    container_name: web
    environment:
      MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_HOST: db
      MYSQL_NAME: ${MYSQL_NAME}
      MYSQL_USER: root
      MYSQL_PORT: 3306
      REDIS_HOST: redis
      REDIS_PORT: 6379
    env_file:
      - ./project.env
    command: supervisord -c /project/confs/supervisord.conf
    volumes:
      - ./files/static:/project/files/static
      - ./files/media:/project/files/media
      - .logs:/opt/logs/
    links:
      - db
      - redis
    depends_on:
      - db
      - redis
    networks:
      - backend
      - frontend

  nginx:
    restart: always
    image: ${NGINX_IMAGE}
    container_name: web_nginx
    volumes:
      - ./files/static:/project/files/static:ro
      - ./files/media:/project/files/media:ro
      - ./confs/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./logs:/var/log/nginx
    ports:
      - "80:80"
      - "443:443"
    links:
      - web
    networks:
      - frontend

networks:
  backend:
    driver: bridge
  frontend:
    driver: bridge

还有一个.env配置文件类配置yml的镜像名和其他参数

DOCKERFILE_NAME=Dockerfile
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=web_db
DOMAIN_NAME=https://yourdomainname
MYSQL_IMAGE=mysql
REDIS_IMAGE=redis
WEB_IMAGE=web
NGINX_IMAGE=nginx

还可以设置一个project.env文件来定义一些参数,在容器运行时加载

DEBUG=False
# MySQL配置
MYSQL_HOST=db
MYSQL_NAME=web_db
MYSQL_USER=root
MYSQL_PASSWORD=123456
MYSQL_PORT=3306
# Redis配置
REDIS_HOST=redis
REDIS_PORT=6379

参数及说明

image:指定服务所使用的镜像

image: mysql

networks 配置容器连接的网络,引用顶级 networks 下的条目 , networks通常应用于集群服务,从而使得不同的应用程序得以在相同的网络中运行,从而解决网络隔离问题,本站点定义了front和back网络,实现了网络隔离。其中redis和db之间只能通过web来实现通信。 aliases :同一网络上的其他容器可以使用服务名称或此别名来连接到对应容器的服务。 network_mode:设置网络模式

network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"

ports:对外暴露的端口定义,和 expose 对应

ports:   # 暴露端口信息  - "宿主机端口:容器暴露端口"
  -"80:80"

links:将指定容器连接到当前连接,可以设置别名,避免ip方式导致的容器重启动态改变的无法连接情况

links:    # 指定服务名称:别名
    - db

volumes:卷挂载路径

volumes:

    - ./db/mysql:/var/lib/mysql

    - /var

logs:日志输出信息

--no-color          单色输出,不显示其他颜.
-f, --follow        跟踪日志输出,就是可以实时查看日志
-t, --timestamps    显示时间戳
--tail              从日志的结尾显示,--tail=200

expose:暴露端口,只将端口暴露给连接的服务,而不暴露给主机

expose:
    - "3306"

environment:环境变量配置,可以用数组或字典两种方式

environment:
      MYSQL_HOST: db
      MYSQL_NAME: web_db
-------------------------
environment:
      - MYSQL_HOST=db
      - MYSQL_NAME=web_db

env_file:从文件中获取环境变量,可以指定一个文件路径或路径列表,其优先级低于 environment 指定的环境变量

env_file:
    - ./peoject.env

command:覆盖容器启动后默认执行的命令

supervisord -c /project/confs/supervisord.conf container_name 前面说过 Compose 的容器名称格式是:<项目名称><服务名称><序号> 虽然可以自定义项目名称、服务名称,但是如果你想完全控制容器的命名,可以使用这个标签指定:

container_name: web 这样容器的名字就指定为 web了。

depends_on 在使用 Compose 时,最大的好处就是少打启动命令,但是一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。 例如在没启动数据库容器的时候启动了应用容器,这时候应用容器会因为找不到数据库而退出,为了避免这种情况我们需要加入一个标签,就是 depends_on,这个标签解决了容器的依赖、启动先后的问题。 例如下面容器会先启动 redis 和 db 两个服务,最后才启动 web 服务:

version: '3'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: mysql

dns:配置 dns 服务器,可以是一个值或列表

dns: 8.8.8.8
------------
dns:
    - 8.8.8.8
    - 9.9.9.9

dns_search:配置 DNS 搜索域,可以是一个值或列表

dns_search: example.com
------------------------
dns_search:
    - dns1.example.com
    - dns2.example.com

配置的文件夹路径和结构一定要对,还有其他的参数没列出,大家需要的话可以去官方文档查看 https://docs.docker.com/get-started/

运行镜像

配置完成后

启动
docker-compose up
停止
docker-compose down

docker-compose也有一些操作命令
ps:列出所有运行容器

docker-compose ps
logs:查看服务日志输出

docker-compose logs
port:打印绑定的公共端口,下面命令可以输出 redis 服务 6379端口所绑定的公共端口

docker-compose port redis 6379
build:构建或者重新构建服务

docker-compose build
start:启动指定服务已存在的容器

docker-compose start eureka
stop:停止已运行的服务的容器

docker-compose stop eureka
rm:删除指定服务的容器

docker-compose rm eureka
up:构建、启动容器

docker-compose up
kill:通过发送 SIGKILL 信号来停止指定服务的容器

docker-compose kill eureka
pull:下载服务镜像

scale:设置指定服务运气容器的个数,以 service=num 形式指定

docker-compose scale user=3 movie=3
run:在一个服务上执行一个命令

docker-compose run web bash

除此之外,docker也可以管理集群,官方也有自己的管理工具,更多内容请查看官网https://www.docker.com/

本文链接:http://nix.pub/article/docker/