本章概述
- 安装docker-compose
- docker-compose常用命令
- 从docker-compose启动单个容器
- 从docker-compose启动多个容器
- 在docker-compose文件中为容器添加不同的网络
- 定义数据卷挂载
- 通过docker-compose实现单机版的 Nginx+Tomcat
前言
当在宿主机启动较多的容器时候,如果都是手动操作会觉得比较麻烦而且容器出错,这个时候推荐使用 docker 单机编排工具 docker-compose,docker-compose是 docker 容器的一种单机编排服务,docker-compose 是一个管理多个容器的工具,比如可以解决容器之间的依赖关系,就像启动一个 nginx 前端服务的时候会调用后端的 tomcat,那就得先启动 tomcat,但是启动 tomcat 容器还需要依赖数据库,那就还得先启动数据库,docker-compose 就可以解决这样的嵌套依赖关系,其完全可以替代 docker run 对容器进行创建、启动和停止。
docker-compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排,docker-compose 将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。工程是指docker-compose所在的目录,服务和k8s中service概念一样,用于管理和访问容器。
备注:docker-compose是单机编排工具,即在一台物理机上启动多个容器时,可以使用该工具
github 地址 https://github.com/docker/compose
7.1 安装docker-compose
注意:安装docker-compose之前,要先安装docker,否则安装docker-compose会报错
7.1.1 pip安装docker-compose
如果可以连外网,可以通过pip安装docker-compose,如果不能连外网,建议通过二进制安装docker-compose。另外,通过pip安装的docker-compose版本相对较低(1.29.2版本),如果想要安装高版本docker-compose,可以通过二进制安装,二进制安装docker-compose的方法请参考8.1.2章节
1、安装python-pip
python-pip 包将安装一个 pip 的命令,pip 命令是一个 pyhton 安装包的安装工具,其类似于 ubuntu 的 apt 或者 redhat 的 yum,但是 pip 只安装 python 相关的安装包,可以在多种操作系统安装和使用 pip。
ubuntu:
root@docker_server01:~# apt update
root@docker_server01:~# apt install python3-pip #当前pip最新版本是pip3,因此安装pip3
centos:
root@docker_server01:~# yum -y install python3-pip
后续操作步骤均一致:
root@docker_server01:~# python3 -m pip install --upgrade pip #升级pip版本,如果不升级,无法安装docker-compsoe
2、安装docker-compose
root@docker_server01:~# pip3 install docker-compose
3、验证docker-compose版本
docker-compose version
7.1.2 二进制安装docker-compose
1、下载docker-compose安装包
github下载页面:https://github.com/docker/compose/releases
使用命令下载docker-compose(2.16.0版本)二进制文件
root@docker_server01:~# cd /usr/local/src
root@docker_server01:~# wget https://github.com/docker/compose/releases/download/v2.16.0/docker-compose-linux-x86_64
2、为二进制文件赋予可执行权限
root@docker_server01:~# chmod a+x docker-compose-linux-x86_64
3、为了便于全局执行命令,把二进制复制到/usr/bin目录下
root@docker_server01:~# cp /usr/local/src/docker-compose-linux-x86_64 /usr/bin/docker-compose
4、验证
执行命令确保docker-compose命令可以执行
root@docker_server01:~# docker-compose version
7.2 docker-compose常用命令
官方文档 https://docs.docker.com/compose/reference/
1、查看docker-compose帮助:
[root@docker-server3 ~]# docker-compose --help
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
选项如下:
-f,–file FILE #指定 Compose 模板文件,默认为 docker-compose.yml。
-p,–project-name NAME #指定项目名称,默认将使用当前所在目录名称作为
项目名。
--verbose #显示更多输出信息
--log-level LEVEL #定义日志级别 (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi #不显示 ANSI 控制字符
-v, --version #显示版本
2、docker-compose命令选项,需要在 docker-compose.yml 文件所在目录执行
带#号的命令均是不常用的命令
#build #通过 docker-compose 构建镜像
#bundle #从当前 docker compose 文件生成一个以当前目录为名称的从 Compose文件生成一个分布式应用程序捆绑包(DAB)。该命令已被废弃,新版本找不到该命令。
config -q #查看当前配置,没有错误不输出任何信息
#create #创建服务
down #停止和删除所有容器、网络、镜像和卷,谨慎使用
#events #从容器接收实时事件,可以指定 json 日志格式,如docker-compose events --json
#exec #进入指定容器进行操作,和docker exec命令功能类似
docker-compose ps --services #获取service名称
docker-compose exec nginx-server bash #根据service名称(nginx_service),进入容器
或docker exec -it nginx-web1 bash #根据容器名称,用docker命令进入容器
help #显示帮助细信息
#images #显示当前服务器的 docker 镜像信息
kill #强制终止运行中的容器
docker-compose kill -s SGIKILL ${docker-compose services名称} #SIG是信号名的通用前缀,KILL是指让一个进程立即终止的动作,合并起来SIGKILL就是发送给一个进程使进程立即终止的信号
logs #查看容器的日志
docker-compose logs --tail=”10” -f nginx-server #查看容器日志,nginx-server是指容器的service名称
#pause #暂停服务
#port #查看端口
docker-compose port --protocol=tcp nginx 80
ps #列出容器
pull #重新拉取镜像
#push #上传镜像
#restart #重启服务
rm #删除已经停止的服务
run #一次性运行容器,等于 docker run --rm
scale #设置指定服务运行的容器个数
docker-compose scale nginx=2
start #启动服务
stop #停止服务
top #显示容器运行状态
unpause #取消暂定
up #创建并启动容器,up -d是指创建容器,运行于后台,如果yml文件做了配置修改,执行该命令会直接根据最新的yml配置文件创建的新的容器
version #显示 docker-compose 版本信息
7.3 从docker-compose启动单个容器
1、创建存放docker-compose.yml文件的目录(目录可以在任意目录,推荐放在有意义的位置)
root@ubuntu:~# mkdir -p /opt/magedu
root@ubuntu:~# cd /opt/magedu
7.3.1 单个容器的docker-compose文件
yml 格式的配置 docker-compose 文件,启动一个 nginx 服务,由于格式为 yml 格式,因此要注意前后的缩进及上下行的等级关系。
root@ubuntu:/opt/magedu# vim docker-compose.yml
version: '3.0'
services:
nginx-server:
image: nginx:v1 #该镜像为之前2.2章节通过dockerfile制作的镜像
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
7.3.2 启动容器
启动命令必须要在 docker compose 文件所在的目录执行:
root@ubuntu:/opt/magedu# pwd
/opt/magedu
root@ubuntu:/opt/magedu#
root@ubuntu:/opt/magedu# docker-compose up -d #-d参数是指容器于后台运行,如果不加,容器于前台运行
查看容器:docker-compose ps 或docker ps命令均可以查看容器
注意:这里由于没有定义容器名称,容器名称是系统自动生成的
7.3.3 web访问验证
浏览器访问172.31.7.150(docker-compose所在主机ip地址)
7.3.4 自定义容器名称
1、修改docker-compose文件
root@ubuntu:/opt/magedu# vim docker-compose.yml
version: '3.0'
services:
nginx-server:
image: nginx:v1 #该镜像为之前2.2章节通过dockerfile制作的镜像
container_name: nginx-web1
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
2、删除已有容器,然后重新创建
root@ubuntu:/opt/magedu# docker-compose down
root@ubuntu:/opt/magedu# docker-compose up -d
3、查看容器
7.4 从docker-compose启动多个容器
7.4.1 编辑docker-compose文件
1、编辑docker-compose文件
root@ubuntu:/opt/magedu# vim docker-compose.yml
version: '3.0'
services:
nginx-server:
image: nginx:v1 #该镜像为之前2.2章节通过dockerfile制作的镜像
container_name: nginx-web1
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
service-tomcat-app1:
image: tomcat-web:app1 #该镜像为之前2.3章节通过dockerfile制作的镜像
container_name: tomcat-app1
expose:
- 8080
- 8443
ports:
- "8080:8080"
- "8443:8443"
7.4.2 启动容器并验证
1、启动容器
root@ubuntu:/opt/magedu# docker-compose up -d
2、验证
查看容器
浏览器访问web页面172.31.7.150:8080/myapp
7.5 为容器添加不同的网络
除了使用默认的网络外,我们还可以给容器添加自定义的网络,而且有时前端和后端容器需要在不同的网络进行隔离,如nginx容器和tomcat容器需要在不同的网段,这样便于管理和维护,需要将不同的容器添加到不同的网络。
7.5.1 将容器加入默认网络
将容器加入默认网络
1、编写docker-compose文件
root@ubuntu:/opt/magedu# vim docker-compose.yml
version: '3.0'
services:
nginx-server:
image: nginx:v1
container_name: nginx-web1 #该镜像为之前2.2章节通过dockerfile制作的镜像
network_mode: bridge #加入网络1,使用docker安装后的默认网桥,注意上下网络名称要保持一致
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
service-tomcat-app1:
image: tomcat-web:app1 #该镜像为之前2.3章节通过dockerfile制作的镜像
container_name: tomcat-app1
expose:
- 8080
- 8443
ports:
- "8080:8080"
- "8443:8443"
networks:
defaults: #使用已经存在的docker0默认172.17.0.1/16的网络,注意上下网络名称要保持一致
name: bridge
external: true
2、启动容器
root@ubuntu:/opt/magedu# docker-compose up -d
3、查看新增网络
4、进入容器查看容器ip地址
7.5.2 将容器加入不同的网络
将前端和后端容器隔离,分别加入不同的网络。我们可以创建两个网络服务:前端服务网络front和后端服务网络backend,用来隔离前端和后端服务。如下图所示:
但nginx作为前端需要访问后端应用服务(如tocmat),将容器加入不同网络后,nginx将无法访问tomcat,为了解决这个问题,我们可以将nginx加入前端和后端两个网络,nginx会自动生成两个网卡,nginx可以通过后端服务网桥访问tomcat服务,如下图所示:
1、编写docker-compose文件
root@ubuntu:/opt/magedu# vim docker-compose.yml
version: '3.0'
services:
nginx-server:
image: nginx:v1 #该镜像为之前2.2章节通过dockerfile制作的镜像
container_name: nginx-web1
#network_mode: bridge #加入网络1,使用docker安装后的默认网桥
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
networks: #加入网络2,会为容器自动创建两个网卡。如果只把nginx加入前端网络,将无法与后端服务通信,因此把nginx加入前端和后端两个网络
- front
- backend
service-tomcat-app1:
image: tomcat-web:app1 #该镜像为之前2.3章节通过dockerfile制作的镜像
container_name: tomcat-app1
expose:
- 8080
- 8443
ports:
- "8080:8080"
- "8443:8443"
networks: #把tomcat加入后端网络
- backend
networks: #自定义两个网络:前端服务网络和后端服务网络
front: #自定义前端服务网络
driver: bridge
backend: #自定义后端服务网络
driver: bridge
#defaults: #使用已经存在的docker0默认172.17.0.1/16的网络
#name: bridge
#external: true
2、创建容器
root@ubuntu:/opt/magedu# docker-compose up -d
3、查看新增网络
4、查看容器网卡信息
查看nginx容器网卡:有两个网卡,并且有不同的网段的ip地址
查看tomcat容器网卡信息
5、测试不同网络的容器通信
在nginx容器测试和tomcat容器是否可以正常通信,可以ping通,这样一来,nginx就可以访问后端tomcat
此时我们只需要在nginx配置中添加代理,将访问myapp页面的请求转发给tomcat即可。
7.6 定义数据卷挂载
1、创建数据目录和文件
root@ubuntu:/opt/magedu# mkdir -p /data/nginx/magedu
root@ubuntu:/opt/magedu# echo "magedu test page" > /data/nginx/magedu/index.html
2、编写docker-compose文件
root@ubuntu:/opt/magedu# vim docker-compose.yml
version: '3.0'
services:
nginx-server:
image: nginx:v1 #该镜像为之前2.2章节通过dockerfile制作的镜像
container_name: nginx-web1
network_mode: bridge #网络1,使用docker安装后的默认网桥
volumes: #自定义存储卷
- /data/nginx/magedu:/apps/nginx/html
expose:
- 80
- 443
ports:
- "80:80"
- "443:443"
service-tomcat-app1:
image: tomcat-web:app1 #该镜像为之前2.3章节通过dockerfile制作的镜像
container_name: tomcat-app1
expose:
- 8080
- 8443
ports:
- "8080:8080"
- "8443:8443"
3、创建容器
root@ubuntu:/opt/magedu# docker-compose up -d
4、web页面验证
7.7 实现单机版的 Nginx+Tomcat
nginx实现动静分离,当访问动态页面时,将请求转发给后端tomcat。而tomcat容器发生变化时,ip地址也会变化,因此nginx配置文件中不能配置tomcat容器ip地址。
为了解决这一问题,docker-compose中有一个links参数,可以将容器名称解析为容器对应ip地址,类似于6.2章节通过容器名称实现不同容器间通信,因此我们可以在docker-compose中添加该参数。
7.7.1 构建haproxy镜像
7.7.1.1 准备工作
1、创建存放dockerfile的目录
mkdir -p /opt/dockerfile/web/haproxy
cd /opt/dockerfile/web/haproxy
2、下载haproxy安装包
haproxy源码包下载网站地址:https://src.fedoraproject.org/repo/pkgs/haproxy/
直接使用命令下载2.4.22版本的haproxy源码包:
root@docker_server01:/opt/dockerfile/web/haproxy# wget https://src.fedoraproject.org/repo/pkgs/haproxy/haproxy-2.4.22.tar.gz/sha512/c22ad38046e3c70beb3bf57a62e4e74db329559059e2f36d2f801768c26b1f1222631702e83e9839fab4396c1b78089a807750ff743b4192da06c751cf9f0779/haproxy-2.4.22.tar.gz
3、准备haproxy配置文件
root@docker_server01:/opt/dockerfile/web/haproxy# vim haproxy.cfg
global
chroot /apps/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
nbproc 1
pidfile /apps/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info
defaults
option http-keep-alive
option forwardfor
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
#haproxy状态页,配置状态页url以及登录的账号密码
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:123456
#haproxy后端应用,加上tomcat容器的地址和端口
listen web_port-80
bind 0.0.0.0:80
mode http
log global
balance roundrobin
server web1 nginx-service:80 check inter 3000 fall 2 rise 5 #这里要添加nginx的service名称,便于haproxy可以通过links参数访问后端nginx容器
listen web_port-443
bind 0.0.0.0:443
mode http
log global
balance roundrobin
server web1 nginx-service:443 check inter 3000 fall 2 rise 5
4、准备haproxy启动脚本
root@docker_server01:/opt/dockerfile/web/haproxy# vim run_haproxy.sh
#!/bin/bash
/apps/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
root@docker_server01:/opt/dockerfile/web/haproxy# chmod a+x run_haproxy.sh
7.7.1.2 编写Dockerfile
1、编写dockerfile
root@docker_server01:/opt/dockerfile/web/haproxy# vim Dockerfile
#haproxy image
FROM centos_base:v1
LABEL maintainer="jack 123456@qq.com"
RUN yum -y install libtermcap-devel ncurses-devel libevent-devel readline-devel gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdump wget ntpdate
ADD haproxy-2.4.22.tar.gz /usr/local/src/
RUN cd /usr/local/src/haproxy-2.4.22 && make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/apps/haproxy && make install PREFIX=/apps/haproxy
#将二进制文件放到/usr/sbin目录
RUN /apps/haproxy/sbin/cp haproxy /usr/sbin/
#创建存放pid文件的目录
RUN mkdir -p /apps/haproxy/run
ADD haproxy.cfg /etc/haproxy/
ADD run_haproxy.sh /usr/bin/
EXPOSE 80 9999
CMD ["/usr/bin/run_haproxy.sh"]
7.7.1.3 构建镜像
1、准备构建镜像的脚本
root@docker_server01:/opt/dockerfile/web/haproxy# vim build-command.sh
#!/bin/bash
docker build -t haproxy:v2.4.22 .
2、执行脚本,构建镜像
root@docker_server01:/opt/dockerfile/web/haproxy# bash build-command.sh
3、查看本地镜像
7.7.1.4 验证
1、根据haproxy镜像启动容器
root@docker_server01:/opt/dockerfile/web/haproxy# docker run -it -p 80:80 -p 9999:9999 haproxy:v2.4.22
2、查看配置文件
7.7.2 构建nginx镜像
7.7.2.1 准备工作
1、创建存放镜像的目录
目录结构按照业务类型或系统类型等方式划分,方便后期镜像比较多的时候进行分类。
root@docker_server01:~# cd /opt
root@docker_server01:~# mkdir dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}} -pv
查看目录结构:
在opt目录下创建dockerfile目录用于存放所有的镜像,然后创建system目录和web目录
system目录用于存放基础镜像,然后根据不同的操作系统,创建相应的目录
web目录用于存放web服务类镜像,然后根据不同类型,创建相应的目录
2、下载centos 7.9.2009镜像
[root@docker-server1 nginx]# docker pull centos:7.9.2009
3、下载nginx 1.16.1版本的源码包
进入到指定的 Dockerfile 目录:
[root@docker-server1 opt]# cd /opt/dockerfile/web/nginx/
root@docker_server01:/opt/dockerfile/web/nginx# wget https://nginx.org/download/nginx-1.16.1.tar.gz
4、准备nginx配置文件
可以使用其它服务器编译安装相同版本的 nginx 配置文件,而且配置文件中关闭 Nginx 进程后台运行
root@docker_server01:/opt/dockerfile/web/nginx# vim nginx.conf
user nginx; #指定启动nginx的用户,需要创建nginx用户
worker_processes auto;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
#这里要写tomcat的service名称(service-tomcat-app1 和service-tomcat-app2),便于nginx容器可以通过tocmat service名称访问后端tomcat容器
upstream tomcat-webserver {
server service-tomcat-app1:8080;
server service-tomcat-app2:8080;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /data/nginx/html; #指定存放代码的目录
index index.html index.htm;
}
location /myapp {
proxy_pass http://tomcat-webserver;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
include /etc/nginx/conf.d/*.conf;
}
7.7.2.2 编写dockerfile
docker在构建镜像过程中,会启动一个容器,在容器内运行dockerfile文件中的指令,运行完成后把容器提交为一个镜像
dockerfile指令在执行命令时,所处的目录和Dockerfile文件处于同一级目录
1、编写dockerfile
root@docker_server01:/opt/dockerfile/web/nginx# vim Dockerfile
#nginx image from centos:7.9.2009
#"#"为注释,等于 shell 脚本的中#
#除了注释行之外的第一行,必须是 From xxx (xxx 是基础镜像)
From centos:7.9.2009
#镜像维护者的信息
MAINTAINER Jack 123456@qq.com
#执行的命令,将编译安装 nginx 的步骤执行一遍
#RUN yum -y install wget
#RUN wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
#RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install epel-release
RUN yum install -y vim wget tree lrzsz gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
ADD nginx-1.16.1.tar.gz /usr/local/src/
RUN cd /usr/local/src/nginx-1.16.1 && ./configure --prefix=/apps/nginx --with-http_sub_module && make && make install
ADD nginx.conf /apps/nginx/conf/nginx.conf
RUN useradd nginx -u 2023
RUN ln -sv /apps/nginx/sbin/nginx /usr/sbin/nginx
RUN mkdir -p /data/nginx/html && echo "test nginx page" > /data/nginx/html/index.html
#向外开放的端口,多个端口用空格做间隔,启动容器时候-p需要使用此端向外映射,如: -p 8081:80,则 80 就是这里的 80
EXPOSE 80 443
#运行的命令,每个 Dockerfile 只能有一条,如果有多条则只有最后一条被执行
CMD ["nginx","-g","daemon off;"]
7.7.2.3 构建镜像
root@docker_server01:/opt/dockerfile/web/nginx# docker build -t nginx:v1 . #注意,在命令最后要加上“.”,表示在当前目录查找构建镜像的文件,如果不加,将会报错
7.7.2.4 启动容器并验证
1、查看本地镜像
2、运行容器并查看
root@docker_server01:/opt/dockerfile/web/nginx# docker run -it -d -p 8088:80 nginx:v1
3、进入容器查看nginx配置文件
7.7.3 构建tomcat镜像
请参考2.3章节,分别构建tomcat-web:app1和tomcat-web:app2镜像
7.7.4 编写docker-compose文件
1、编写docker-compose文件(由于tomcat和nginx属于内部应用,因此无需暴露端口,之前暴露端口是为了验证镜像是否可用,验证完成后,可以把暴露端口去掉)
vim docker-compose.yml
version: '3.0'
services:
service-haproxy:
image: haproxy:v2.4.22
container_name: haproxy
expose:
- 80
- 443
- 9999
ports:
- "80:80"
- "443:443"
- "9999:9999"
links:
- nginx-service
nginx-service:
image: nginx:v1 #该镜像为之前2.2章节通过dockerfile制作的镜像
container_name: nginx-web1
service-tomcat-app1:
image: tomcat-web:app1 #该镜像为之前2.3章节通过dockerfile制作的镜像
container_name: tomcat-app1
service-tomcat-app2:
image: tomcat-web:app2 #该镜像为之前2.3章节通过dockerfile制作的镜像
container_name: tomcat-app2
7.7.5 启动容器并验证
1、启动容器
root@ubuntu:/opt/magedu# docker-compose up -d
2、通过web页面访问验证
由于nginx访问tomcat属于轮询,因此访问时会出现以下两个页面轮询出现的现象
文章评论