本章经过一个具体的demo来了解 docker-compose
在构建一个完整的服务时,咱们一般启动一个容器, 一旦出现多个容器须要同时启动的时候手打是下下之策, 由于时间一长不免会忘记细节,写脚本也不是不能够,可是你们没有达成共识时脚本也很难维护...php
docker-compose
就是来解决这个痛点, 只须要按照统一的格式书写,那么你们生成的容器也都是一致的, 在团队开发的时候扔一个配置好的 docker-compose
能节省不少时间和口水html
这是我构建的一个开发环境的容器:dnmpmysql
首先下载下来nginx
git clone https://github.com/gaopengfei123123/dnmp.git && cd dnmp
咱们第一件事就是先瞄一眼 .env
文件, 这里设置了不少常量,一会根据我的需求来调整git
第二步才是打开 docker-compose.yml
文件, 看后缀都能猜到这是一个配置文件, 另外 docker-compose.yml
是根据缩进来进行分层的,注意书写格式github
# 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-nginx build: context: ./nginx args: - PHP_UPSTREAM_CONTAINER=${NGINX_PHP_UPSTREAM_CONTAINER} - PHP_UPSTREAM_PORT=${NGINX_PHP_UPSTREAM_PORT} depends_on: - php-fpm ports: - "${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-fpm args: - PHP_VERSION=${PHP_VERSION} volumes: - ${APP_CODE_PATH_HOST}:/var/www - ./php-fpm/php${PHP_VERSION}.ini:/usr/local/etc/php/php.ini expose: - "9000" networks: - backend redis: container_name: dnmp-redis build: context: ./redis args: - REDIS_SET_PASSWORD=${REDIS_SET_PASSWORD} ports: - ${REDIS_HOST_PORT}:6379 volumes: # 这里卷挂载的是本地文件 # - ${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/Dockerfile image: mysql:${MYSQL_VERSION} volumes: # - ${DATA_PATH_HOST}/mysql:/var/lib/mysql - mysql_volume:/var/lib/mysql # 容器只要中止就会重启 restart: always environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} ports: - ${MYSQL_HOST_PORT}:3306
接下来看看它的关键词都起着什么做用:redis
这个规定了文件的版本, 既然有 3 就确定不用 2 啊, 虽然二者没冲突,可是我喜欢, 2 和 3 版本之间有轻微的变更,具体区别你能够在写配置文件时产生的报错信息来体验一下sql
networks: frontend: driver: ${NETWORKS_DRIVER} backend: driver: ${NETWORKS_DRIVER}
${NETWORKS_DRIVER}
是从 .env
文件中取的值, 下面的同理docker
这一块就至关于执行 docker network create -d bridge frontend && docker network create -d bridge backend
在本地持久化的创建一个网络配置,稍后方便容器进行链接, 固然这里也不止是一个 driver
参数,具体配置状况仍是参考docker network inspect dnmp_frontend
来看一下segmentfault
没有设置名字的配置当须要名字的时候会 {当前docker-compose.yml文件名}_{key}
这种格式
有了 network
配置就极大的简化了老版的 --links
命令, 只要属于同一个 network 就能互相访问到, 而不是每新增一个服务就要把原来的服务都 link 一遍
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
就不必这么搞了
这个是本章的重点, 咱们来看下面的例子中的注释, 按序号来
services: #1 建立一个服务叫作nginx服务 nginx: #2 为了显得个性化一点,咱们指定这个容器的名字叫作 dnmp-nginx container_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=zzz context: ./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/sites COPY ./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 名称就行
这里须要注意的时 ARG
和 ENV
的区别, 参考这篇文章: Docker中 Arg 和 Env 的区别
在配置好 .env
文件和 docker-compose.yml
配置文件后就能够启动它了, 命令也很简单,在同级目录下运行:
docker-compose up -d
它会自动建立volume
,network
,services
, 并且相关的运行参数都是按着配置文件来的, 这样一来每一个完整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, 它如今作的太臃肿了。。。。 看看它里面的镜像是怎么写的仍是颇有收获的