本章通过一个具体的demo来了解 docker-compose

docker-compose 是做什么的

在构建一个完整的服务时,我们通常启动一个容器, 一旦出现多个容器需要同时启动的时候手打是下下之策, 因为时间一长难免会忘记细节,写脚本也不是不可以,但是大家没有达成共识时脚本也很难维护…

docker-compose 就是来解决这个痛点, 只需要按照统一的格式书写,那么大家生成的容器也都是一致的, 在团队开发的时候扔一个配置好的 docker-compose 能节省很多时间和口水

配置 docker-compose

这是我构建的一个开发环境的容器:dnmp

首先下载下来

git clone https://github.com/gaopengfei123123/dnmp.git && cd dnmp

我们第一件事就是先瞄一眼 .env 文件, 这里设置了很多常量,一会根据个人需求来调整

第二步才是打开 docker-compose.yml 文件, 看后缀都能猜到这是一个配置文件, 另外 docker-compose.yml 是根据缩进来进行分层的,注意书写格式

# docker-compose.yml
# 语法版本( 3 和 2 区别有点大, 比如 3 取消了 volume_from 的相关语法)
version: "3"networks:frontend:driver: ${NETWORKS_DRIVER}backend:driver: ${NETWORKS_DRIVER}volumes:mysql_volume:driver: ${VOLUMES_DRIVER}redis_volume:driver: ${VOLUMES_DRIVER}rabbitmq_volume:driver: ${VOLUMES_DRIVER}
# 服务编排
services:# workspace:#   image: tianon/true#   container_name: dnmp-www#   volumes:#     - ./www:/usr/share/nginx/html# NGINX #############################################nginx:container_name: dnmp-nginxbuild: context: ./nginxargs:- PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER}- PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT}depends_on:- php-fpmports:- "${NGINX_HOST_HTTP_PORT}:80"- "${NGINX_HOST_HTTPS_PORT}:443"volumes:# 没必要把配置文件用卷来挂载, 不然就算配置更新了 nginx 也是要重启的# 挂载运行代码目录- ${APP_CODE_PATH_HOST}:/var/www# 挂载日志目录- ${NGINX_HOST_LOG_PATH}:/var/log/nginx# 使用 networks 取代 links 在同一个网络模式下的服务是互通的# 在service 中使用其他的 service 就直接调用 service 名就行, 不用管 ip 地址, docker 会自己维护一套networks:- frontend- backend# PHP-FPM #############################################php-fpm:container_name: dnmp-php-fpm# 这里的args 是属于 build 下面的,用于构建./php-fpm/Dockerfile 文件中 ARG 参数指定 php 版本build: context: ./php-fpmargs:- PHP_VERSION=${PHP_VERSION}volumes:- ${APP_CODE_PATH_HOST}:/var/www- ./php-fpm/php${PHP_VERSION}.ini:/usr/local/etc/php/php.iniexpose:- "9000"networks:- backendredis:container_name: dnmp-redisbuild:context: ./redisargs:- REDIS_SET_PASSWORD=${REDIS_SET_PASSWORD}ports:- ${REDIS_HOST_PORT}:6379volumes:# 这里卷挂载的是本地文件# - ${DATA_PATH_HOST}/redis:/data# 这里创建一个 redis_volume来存放数据- redis_volume:/data# Mysql #############################################mysql:container_name: dnmp-mysql# 镜像来源: https://github.com/docker-library/mysql/blob/fc3e856313423dc2d6a8d74cfd6b678582090fc7/5.7/Dockerfileimage: mysql:${MYSQL_VERSION}volumes:# - ${DATA_PATH_HOST}/mysql:/var/lib/mysql- mysql_volume:/var/lib/mysql# 容器只要停止就会重启restart: alwaysenvironment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}MYSQL_DATABASE: ${MYSQL_DATABASE}MYSQL_USER: ${MYSQL_USER}MYSQL_PASSWORD: ${MYSQL_PASSWORD}ports:- ${MYSQL_HOST_PORT}:3306

接下来看看它的关键词都起着什么作用:

version

这个规定了文件的版本, 既然有 3 就肯定不用 2 啊, 虽然两者没冲突,但是我喜欢, 2 和 3 版本之间有轻微的变动,具体区别你可以在写配置文件时产生的报错信息来体验一下

network
networks:frontend:driver: ${NETWORKS_DRIVER}backend:driver: ${NETWORKS_DRIVER}

${NETWORKS_DRIVER} 是从 .env 文件中取的值, 下面的同理

这一块就相当于执行 docker network create -d bridge frontend && docker network create -d bridge backend
在本地持久化的建立一个网络配置,稍后方便容器进行连接, 当然这里也不止是一个 driver 参数,具体配置情况还是参考docker network inspect dnmp_frontend 来看一下

没有设置名字的配置当需要名字的时候会 {当前docker-compose.yml文件名}_{key} 这种格式

有了 network 配置就极大的简化了老版的 --links 命令, 只要属于同一个 network 就能互相访问到, 而不是每新增一个服务就要把原来的服务都 link 一遍

volume
volumes:mysql_volume:driver: ${VOLUMES_DRIVER}redis_volume:driver: ${VOLUMES_DRIVER}rabbitmq_volume:driver: ${VOLUMES_DRIVER}

network 部分一样, 持久化的创建几个 volume, 相当于命令 docker network create mysql_volume等等

这算是 v3 的一个新特性, 在 v2 的时候, 为了共享数据大家会创建一个什么镜像都不继承的image, 所有容器的 volume 都会和它连接, 现在有了 volume 就没必要这么搞了

service

这个是本章的重点, 我们来看下面的例子中的注释, 按序号来

services:#1 创建一个服务叫做nginx服务nginx:#2 为了显得个性化一点,我们指定这个容器的名字叫做 dnmp-nginxcontainer_name: dnmp-nginx#3 标明这个服务的 Dockerfile 的地址,用相对路径方便项目迁移build: #3.1 相当于命令: # docker build ./nginx -t dnmp-nginx \#     --build-arg PHP_UPSTREAM_CONTAINER=xxx \#     --build-arg PHP_UPSTREAM_PORT=zzzcontext: ./nginx#3.2 这里 ${NGINX_PHP_UPSTREAM_PORT} 的值是从 .env 文件中取的, args 属于构建时传入的参数args:- PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER}- PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT}#4  在启动这个容器之前先启动 php-fpm 这个容器 depends_on:- php-fpm#5 将本地端口和容器端口绑定, 本地哪个端口就看 .env 里怎么写的ports:- "${NGINX_HOST_HTTP_PORT}:80"- "${NGINX_HOST_HTTPS_PORT}:443"#6 设置需要挂载的卷, 这里时将本地目录和容器绑定, 也可以像 services.redis 那样和创建好的卷绑定 volumes:# 没必要把配置文件用卷来挂载, 不然就算配置更新了 nginx 也是要重启的# 挂载运行代码目录- ${APP_CODE_PATH_HOST}:/var/www# 挂载日志目录- ${NGINX_HOST_LOG_PATH}:/var/log/nginx# 使用 networks 取代 links 在同一个网络模式下的服务是互通的# 在service 中使用其他的 service 就直接调用 service 名就行, 不用管 ip 地址, docker 会自己维护一套#7 设置容器从属的网络, 同一个网络下可互相访问networks:- frontend- backend

在上文的 #3 步骤看其他的service也有直接使用image的, 这是直接从远程获取镜像的方式

配置文件写完了, 我们看下nginx的构建文件

# in file ./nginx/Dockerfile#1 选择继承的镜像
FROM nginx:1.13.1-alpine
#2 各种标签
LABEL maintainer="GPF <5173180@qq.com>"#3 容器中执行命令, 且把本地的配置文件添加进去
#https://yeasy.gitbooks.io/docker_practice/content/image/build.html
RUN mkdir -p /etc/nginx/cert \&& mkdir -p /etc/nginx/conf.d \&& mkdir -p /etc/nginx/sitesCOPY ./nginx.conf /etc/ngixn/nginx.conf
COPY ./conf.d/ /etc/nginx/conf.d/
COPY ./cert/ /etc/nginx/cert/COPY ./sites /etc/nginx/sites/#4 这里也是设置构建参数, 不过相同 key 值会被 docker-compose 中的给覆盖掉
ARG PHP_UPSTREAM_CONTAINER=php-fpm
ARG PHP_UPSTREAM_PORT=9000
#5 ${PHP_UPSTREAM_CONTAINER} 就在构建时的参数使用方式
RUN echo "upstream php-upstream { server ${PHP_UPSTREAM_CONTAINER}:${PHP_UPSTREAM_PORT}; }" > /etc/nginx/conf.d/upstream.conf#6 设置挂载的目录, 该目录下文件变化不会影响到容器
VOLUME ["/var/log/nginx", "/var/www"]#7 设置目录运行时所处在容器中的目录地址
WORKDIR /usr/share/nginx/html

#5 就是显示了在 nginx 容器中怎么去访问 php-fpm 这个容器, 直接调用 service 名称就行

这里需要注意的时 ARGENV 的区别, 参考这篇文章: Docker中 Arg 和 Env 的区别

启动docker-compse

在配置好 .env 文件和 docker-compose.yml 配置文件后就可以启动它了, 命令也很简单,在同级目录下运行:

docker-compose up -d

它会自动创建volumenetworkservices, 而且相关的运行参数都是按着配置文件来的, 这样一来每个完整docker-compose.yml中的service就相当于时一个整体,每个服务又属于各自的容器,这样操控是不是节省了很多代码呢?

查看这些容器的运行状况也很是简单

docker-compose ps
# 或者使用更方便的一个工具: ctop , github地址: https://github.com/bcicen/ctop

可操控单一容器一样, 但是它会把这一组容器都囊括了进去,操控起来只需要知道操控哪个服务,而一些参数就写在配置文件当中已经默认添加了

一些常用的命令:

# 终止整个服务集合
docker-compose stop# 终止指定的服务 (这有个点就是启动的时候会先启动 depond_on 中的容器,关闭的时候不会影响到 depond_on 中的)
docker-compose stop nginx# 查看容器的输出日志
docker-compose logs -f [services...]# 构建镜像时不使用缓存(能避免很多因为缓存造成的问题)
docker-compose build --no-cache --force-rm# 移除指定的容器
docker-compose rm nginx

本来熟悉命令的最好方式就是 用->犯错->排错->用 这种循环, 有什么不懂的 谷歌bing 都能查到, 直接 docker-compose --help 也能猜出命令的大概作用, 这里就不细说了

还有个很不错的 docker-compose 项目就是 laradock, dnmp 就是仿照着它写的, 不过网络不好的情况下别运行 laradock, 它现在做的太臃肿了。。。。 看看它里面的镜像是怎么写的还是很有收获的

参考

https://deepzz.com/post/docker-compose-file.html
https://andyoung.blog.csdn.net/article/details/107919246

Docker(十五):Docker实战 使用 docker-compose相关推荐

  1. Docker知识五:服务编排(Docker Compose概念)

  2. Docker(五)进阶:Docker卷(volumes)

    目录 前言 一.在Docker中管理数据 1.为什么要挂载? 2.选择正确的挂载方式 二.卷(volume) 1.卷的概述 2.卷的优点 3.卷的使用 4.实战:持久化数据 1)MySQL容器为什么挂 ...

  3. Android学习笔记(十五)——实战:强制下线

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 实现强制下线功能的思路也比较简单,只需要在界面上弹出一个对话框, 让用户无法进行任何其他操作, 必须要点击对话 ...

  4. 分式加法JAVA程序_十五:实战2-分式计算器

    概述 通过前几节课我们学习了Java中对象类的属性,方法,构造方法,封装等相关知识,这节课通过一个分式计算器项目来练习Java类的知识.分式由两个部分组成:分子和分母,在本项目中需要定义两个类,Fra ...

  5. 阿里云CentOS环境之-实战docker集群swarm(十五)

    前言 docker1.12版本之前版本配置 准备工作 开始 拉取swarm 开放2375远程访问端口 创建集群的token 向集群里添加结点 查看集群里有哪些结点 创建管理者容器 使用集群 离开集群 ...

  6. Docker最全教程之MySQL容器化 (二十五)

    前言 MySQL是目前最流行的开源的关系型数据库,MySQL的容器化之前有朋友投稿并且写过此块,本篇仅从笔者角度进行总结和编写. 目录 镜像说明  运行MySQL容器镜像  1.运行MySQL容器  ...

  7. Docker最全教程之Ubuntu下安装Docker(十五)

    前言 Ubuntu是一个以桌面应用为主的开源GNU/Linux操作系统,应用很广.本篇主要讲述Ubuntu下使用SSH远程登录并安装Docker,并且提供了Docker安装的两种方式,希望对大家有所帮 ...

  8. 实战:Docker容器虚拟化技术(使用DockerFile构建镜像并搭建 swarm+compose集群)5

    实战:Docker容器虚拟化技术 (使用DockerFile构建镜像并搭建 swarm+compose集群)5 要求: 使用DockerFile构建镜像并搭建 swarm+compose集群 在Swa ...

  9. DockOne微信分享(八十五):Docker存储方式选型建议

    本文讲的是DockOne微信分享(八十五):Docker存储方式选型建议[编者的话]Docker存储方式提供管理分层镜像和容器的可读写层的具体实现.最初Docker仅能在支持AUFS文件系统的Ubun ...

最新文章

  1. 采购申请的处理流程 --- 责任链模式
  2. 用户进程与内核进程是一一对应的吗_用户线程、内核线程和轻量级进程
  3. 多线程程序在多核和单核上运行的不同
  4. MySQL搭建主从复制架构实战
  5. SAP产品增强技术回顾
  6. 远程ykvm 插件移值java_Centos7 命令行下kvm安装windows,linux
  7. 5b计算机联锁系统_力控科技油库调度管理系统应用案例
  8. 未来教育计算机二级第一套ppt解析,计算机二级未来教育PPT部分答案
  9. 舰船目标检测的学习笔记
  10. eclipse打不开,报错 java was started with exit code=13
  11. IoT:大端与小端字节数据详解
  12. 像素测量工具_结构光视觉传感器的标定方式和测量原理
  13. zabbix获取mysql主从状态_zabbix监控MySQL主从状态
  14. java mvc 登陆_SpringMVC实现用户登录实例
  15. 陪孩子一起学习python
  16. SOUI::SStatic 动态设置属性的值
  17. 《MarkDown编辑器的使用技巧(修改录入方式与目录生成)|CSDN编辑器测评》
  18. PCBA可靠性测试有哪些?
  19. 【需求】Python利用selenium抓取顺丰的地址数据
  20. 半球展开图_新手入门如何学习钣金放样展开,老师傅分享篇(二)!

热门文章

  1. NBT:PICRUSt2预测宏基因组功能
  2. SBB:南土所褚海燕组-pH主导土壤中固氮群落的共存与装配
  3. 一作解读Gut:人体最初的微生物起源与生殖健康
  4. pandas使用idxmin函数获取dataframe每个数据行中最小值对应的列名称(column label of min value in each row in dataframe)
  5. python使用matplotlib对比多个模型在测试集上的效果并可视化、设置模型性能可视化结果柱状图(bar plot)标签的小数点位数(例如,强制柱状图标签0.7显示为两位小数0.70)
  6. R语言使用apriori算法进行关联规则挖掘实战:关联规则概念、频繁项集、支持度(support)、置信度(confidence)、提升度(lift)、apriori算法
  7. R语言shapiro.test()函数实现Shapiro-Wilk正态分布检验
  8. python代码根据当前时间获取下一周的日期
  9. 绘制测试集、训练集的每一个病人或者样本的raidomics signiture图(绘制raidomics signature图),以及ROC曲线图
  10. 生物信息学就是从统计和CS的community里借鉴合适的方法