Docker-compose容器编排技术

一、Docker-Compose的安装

1. 规划节点

IP 主机名 节点
192.168.200.10 master docker-compose

2. 基础准备

登录OpenStack平台,使用提供的CentOS_7.5_x86_64_XD.qcow2镜像创建云主机,软件包docker- compose.tar.gz上传到/root目录下

3. 基础环境准备

3.1配置yum源

上传文件&解压文件&配置yum源

# 解压文件到/opt/ 
master # tar -zxvf docker-compose.tar.gz -C /opt/
# 备份原来的yum文件
master # gzip /etc/yum.repos.d/*
# 配置yum文件
master # vi /etc/yum.repos.d/docker.repo
[docker]
name=docker
baseurl=file:///opt/docker-compose
gpgcheck=0
enabled=1

3.2 配置主机映射

配置主机映射

master # vi /etc/hosts ...... 192.168.200.10 master ​

3.3 配置防火墙以及SElinux

配置防火墙以及SElinux

# 清除所有定制的规则 
master # iptables -F
# 清除所有用户“自定义”的chain
master # iptables -X
# 将所有的chain的计数与流量统计都归零
master # iptables -Z
master # iptabes-save
master # sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
master # reboot

3.4 关闭swap分区

Swap分区通常被称为交换分区,当实际内存不够用的时候,操作系统会从内存中取出一部分暂时不用的数据,放在交换分区中,从而为当前运行的程序腾出足够的内存空间。但是频繁的读写硬盘,会显著降低操作系统的运行速率。

永久禁用虚拟内存:

master # swapoff -a 
master # sed -i 's/.*swap.*/#&/' /etc/fstab

3.5 配置路由转发

RHEL/CentOS7上的一些用户报告了由于iptables被绕过而导致流量路由不正确的问题,所以需要在各节点开启路由转发,确保iptables工具可以处理网桥流量。

开启路由转发功能:

master # cat << EOF | tee /etc/sysctl.d/k8s.conf 
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF ​

3.6 安装docker

安装相关工具:

master # yum -y install -y yum-utils device-mapper-persistent-data lvm2

安装Docker:

master # yum install -y docker-ce 
master # systemctl start docker.service && systemctl enable docker.service

Docker从v1.6.15开始到v2.x.x,Docker系统相关的所有镜像都托管在Dockerhub仓库。Dockerhub节点在国外,国内直接拉取镜像会有些缓慢。为了加速镜像的下载,可以通过参数“registry-mirrors”给Docker配置国内的镜像地址。

Docker默认只信任TLS加密的仓库地址(https),所有非https仓库默认无法登录和拉取镜像。“insecure-registries”参数字面意思为不安全的仓库,通过添加这个参数对非https仓库进行授信。可以设置多个insecure-registries地址,以数组形式书写,地址不能添加协议头(http)。

OverlayFS是一个新一代的联合文件系统,类似于AUFS,但速度更快,实现更简单。Docker为OverlayFS提供了两个存储驱动程序:旧版的overlay和新版的overlay2(更稳定),通过“storage-driver”参数配置其文件系统。

容器在运行时会产生大量日志文件,很容易占满磁盘空间,可通过“log-opts”字段配置日志驱动来限制文件大小与文件的数量。

daemon.json文件配置如下:

master # cat > /etc/daemon.json << EOF { "insecure-registries":["0.0.0.0/0"], "registry-mirros":["https://7bezldxe.mirror.aliyuncs.com/"], "exec-opts":["native.cgroupdriver=cgroupfs"] } EOF

重启Docker:

master # systemctl restart docker.service

导入镜像:

master # docker load -i /opt/offline_images.tar

4. 部署DockerCompoes

Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。Compose允许用户通过一个单独的docker-compose.yaml模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)。Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此只要所操作的平台支持Docker API,就可以在其上利用Compose来进行编排管理。

Docker-Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container)。Docker-Compose运行目录下的所有文件(docker-compose.yml,extends文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像,参数,依赖。一个服务当中可包括多个容器实例,Docker-Compose并没有解决负载均衡的问题,因此需要借助其它工具实现服务发现及负载均衡。

Docker-Compose的工程配置文件默认为docker-compose.yml,可通过环境变量COMPOSE_FILE或-f参数自定义配置文件,其定义了多个有依赖关系的服务及每个服务运行的容器。

使用一个Dockerfile模板文件,可以让用户很方便的定义一个单独的应用容器。在工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个Web项目,除了Web服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

4.1安装Docker-Compose

安装DockerCompose:

master # cd /opt/ 
master # chmod +x v1.25.5-docker-compose-Linux-x86_64
master # mv v1.25.5-docker-compose-Linux-x86_64 /usr/local/bin/docker-compose

查看版本信息

master # docker-compose version

二、Docker-Compose编排部署服务

1. 规划节点

IP 主机名 节点
192.168.200.10 master docker-compose

2. 基础准备

Docker-ce和DockerCompose已经安装完成

3. YAML知识补充

YAML是“YAML Ain't a Markup Langua”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。

YAML的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。

YAML的配置文件后缀为.yml或.yaml,如test.yml。

YAML的基本语法规则:

  • 大小写敏感

  • 使用缩进表示层级关系

  • 缩进时不允许使用tab建,只允许使用空格

  • 缩进的空格数目不重要,只要相同层级的元素左侧对其即可。

YAML支持的数据结构如下

  • 对象:键值对的集合,又称为映射(mapping)/哈希(hashes)/字典(dictionary)

  • 数组:一组按次序排列的值,又称为序列(sequence)/列表(list)

  • 纯量(scalars):单个的、不可再分的值

3.1YAML对象

对象键值对使用冒号结构表示key:value,冒号后面要加一个空格。

也可以使用key{key1:value1,key2:value2,key3:value3...}。

还可以使用缩进表示层级关系

key:    child-key: value    child-key: value2

较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的key,配合一个冒号加一个空格代表value

?     - complexkey1    - complexkey2 :    - complexvalue1    - complexvalue2

意思即对象的属性是一个数组[complexkey1,complexkey2],对应的值也是一个数组[complexvalue1,complexvalue2]。

3.2YAML数组

以 - 开头的行表示构成一个数组:

- A - B - C

YAML支持多维数组,可以使用行内表示:

key: [value1,value2,...]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格。

-     - A    - B    - B

一个相对复杂的例子:

companies:   -     id: 1    name: company1    price: 200W  -     id: 2    name: company2    price: 500W

意思就是companies属性是一个数组,每一个数组元素又是由id、mane、price三个属性构成

数组也可以使用流式(flow)的方式表示:

companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]

3.3复合结构

数组和对象可以构成复合结构,例:

languages:   - Ruby  - Perl  - Python websites:   YAML: yaml.org  Ruby: ruby-lang.org  Python: python.org  Perl: use.perl.org

转换为json为:

{ languages: ['Ruby'.'Perl','Python'], websites: {     YAML: 'yaml.org',     Ruby: 'ruby-lang.org',     Python: 'python.org',     Perl: 'use.perl.org' } }

3.4纯量

纯量是最基本的,不可再分的值,包括:

  • 字符串

  • 布尔值

  • 整数

  • 浮点数

  • Null

  • 时间

  • 日期

    使用一个例子来快速了解纯量的基本使用:

boolean:   - TRUE # true,Trur都可以  - FALSE # false,False都可以 float:   - 3.14  - 6.8523015e+5 # 可以使用科学计数法 int:   - 123  - 0b1010_0111_0100_1010_1110 # 二进制表示 null:   nodeName: 'node'  parent: ~ # 使用~表示null string:   - 哈哈  - 'Hello world' # 可以使用双引号或单引号表过特殊字符  - newline    newline2 # 字符串可以拆成多行,每一行会被转化成一个空格 date:   - 2021-09-17 # 日期必须使用ISO 8601格式,即yyyy-MM-dd datetime:   - 2021-09-17T08:00:00+08:00 # 时间使用ISO 8601格式,时间和日期之间使用T链接,最后使用+代表时区

3.5引用

“&”和“*”可以用来引用:

defaults: &defaults  adapter: postgres  host: localhost    development:  database: myapp_development  <<: *defaults    test:   database: myapp_test  <<: *defaults

相当于:

defaults: &defaults  adapter: postgres  host: localhost    development:  database: myapp_development  adapter: postgres  host: localhost    test:   database: myapp_test  adapter: postgres  host: localhost

&用来建立锚点(dafaules),<< 表示合并到当前数据,*用来引用锚点。

下面是另一个例子:

- &showell Steve - Clark - Brian - Oren - *showell

4. Dockerfile知识补充

Dockerfile是一个包含用于组合镜像的命令的文本文档。可以使用在命令行中调用任何命令。Docker通过读取Dockerfile中的指令自动生成镜像。

Dockerfile一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,“#”为Dockerfile中的注释。

Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本镜像,第一条指令必须是FROM。一个声明以“#”字符开头则被视为注释。可以在Docker文件中使用RUN、CMD、FROM、EXPOSE、ENV等指令。

4.1基础指令

FROM用于指定基础镜像,必须为第一个命令。格式如下:

FROM  FROM : FROM @

示例:

FROM mysql:5.6

tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像

MAINTAINER用于指定维护者信息,格式如下:

MAINTAINER 

示例:

MAINTAINER Double MAINTAINER [email protected] MAINTAINER Double 

RUN用于构建镜像时执行的命令。

RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:

shell执行方式的格式:

RUN 

exec执行方式的格式如下:

RUN ["executable","param1","param2"]

示例:

RUN ["executable","param1","param2"] RUN apk update RUN ["/ect/execfile","arg1","arg2"]

RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache。

ADD用于将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被加压),可以访问网络资源,类似wget。格式如下:

ADD ... ADD ["",...""] # 用于支持包含空格的路径

示例:

ADD hom* /mydir/ # 添加所有以"hom"开头的文件 ADD hom?.txt /mydir/ # ?替代一个单字符,例如:"home.txt" ADD test relativeDir/ # 添加"test"到`WORKDIR`/relativeDir/ ADD test /absoluteDir/ # 添加"test"到/absoluteDir/

COPY的功能类似ADD,但是不会自动解压文件,也不能访问网络资源。

CMD用于构建容器后调用,也就是在容器启动时才进行调用,格式如下:

CMD ["executable","param1","param2"](执行可执行文件,优先) CMD ["param1","param2"](设置了ENTRYPOINT,则直接调用ENTROPOINT添加参数) CMD command param1 param2 (执行shell内部的命令)

示例:

CMD echo "This is a test." wc - CMD ["/usr/bin/wc","--help"]

CMD不同于RUNCMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

ENTRYPOINT用于配置容器,使其可执行化。配合CMD可省去"application",只使用参数,格式如下:

ENTRYPOINT ["executable","param1","param2"](可执行文件,优先) ENTRYPOINT command param1 param2 (shell内部命令)

示例:

FROM ubuntu ENTRYPOINT ["top","-b"] CMD ["-c"]

ENTRYPOINTCMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当作参数再次传递给ENTRYPOINTDockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。

LABEL用于为镜像添加元数据。格式如下:

LABEL ===...

示例:

LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"

使用LABEL指定元数据时,一条LABEL可以指定一条或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过LABEL指令指定,以免生成过多的中间镜像。

ENV用于设置环境变量。格式如下:

ENV   #  之后所有的内容均会被视为其的组成部分,因此,一次只能设置一个变量。 ENV = ... # 可以设置多个变量,每个遍历为一个=的键值对,如果中包含空格,可以使用\来转义,也可以通过""进行标识;另外,反斜线也可以用于续行

示例:

ENV myName Join Doe ENV myDog Rex The Dog ENV myCat=fluffy

EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。

VOLUME用于指定 持久化目录。格式如下:

VOLUME ["/path/to/dir"]

示例:

VOLUME ["/data"] VOLUME ["/var/www","/var/log/apache2","/etc/apache2"]

一个卷可以存在与一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:

  1. 卷可以容器之间共享和重用

  2. 容器并不一定要和其他容器共享卷

  3. 修改卷后会立即生效

  4. 对卷的操作不会对镜像产生影响

  5. 卷会一直存在,直到没有任何容器使用它

    WORKDIR用于指定工作目录,类似cd命令。格式如下:

WORKDIR /path/to/workdir

示例:

WORKDIR /a (这时工作路径为/a) WORKDIR b (这时工作目录为/a/b) WORKDIR c (这时工作目录为/a/b/c)

通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUNCMDENTRYPOINTADDCOPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录

USER用于指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UIDGID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户。格式如下:

USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group

示例:

USER www

使用USER指定用户后,Dockerfile中其后的命令RUNCMDENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。

ARG用于指定传递给构建运行时的变量。格式如下:

ARG [=]

示例:

ARG site ARG build_user=www

NBUILD用于设置镜像触发器。格式如下:

ONBUILD [INSTRUCTION]

示例:

ONBUILD ADD ./app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src

当所构建的镜像被利用作其他镜像的基础镜像,该镜像中的触发器会被触发。

4.2Dockerfile案例

首先准备一个linux的基础镜像:

master # docker images REPOSITORY         TAG         IMAGE ID         CREATED     SIZE centos       centos7.5.1804     cf49811e3cdb        19 months ago     200MB ​

在一个空白目录中,准备好相应的软件包,并建立一个文本文件,并命名为Dockerfile:

master # mkdir mydocker master # cd mydocker master # cp -rvf /opt/jdk-8u141-linux-x64.tar.gz .

构建一个Dockerfile 内容如下:

master # vi Dockerfile# build a new image with basic centos FROM centos:centos7.5.1804 # who is the author MAINTAINER Double # make a new directory to store the jdk files RUN mkdir /usr/local/java # copy the jdk archive to the image,and it will automaticlly unzip the tar file ADD jdk-8u141-linux-x64.tar.gz /usr/local/java/ # make a symbol link RUN ln -s /usr/local/java/jdk1.8.0_141 /usr/local/java/jdk # set environment variable ENV JAVA_HOME /usr/local/java/jdk ENV JRE_HOME ${JAVA_HOME}/jre ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib ENV PATH ${JAVA_HOME}/bin:$PATH

根据Dockerfile创建新镜像:

master # docker build -t="centos-jdk" . ...... Successfully built cd9b1e5aaae3 Successfully tagged centos-jdk:latest

查看新建立的镜像:

master # docker images REPOSITORY       TAG         IMAGE ID           CREATED       SIZE centos-jdk       latest         cd9b1e5aaae3        46 minutes ago     576MB centos       centos7.5.1804       f49811e3cdb         19 months ago     200MB

建立容器,查看新的镜像中的JDK是否正确:

master # docker run -it centos-jdk /bin/bash 8aabd21e9def # java -version java version "1.8.0_141" Java(TM) SE Runtime Environment (build 1.8.0_141-b15) Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode) 8aabd21e9def # echo $JAVA_HOME /usr/local/java/jdk 8aabd21e9def # exit

4.3Compose的基本使用

(1)准备

创建一个测试目录:

master # mkdir composetest master # cd composetest

在测试目录中创建一个名为app.py的文件,内容如下:

matest # vi app.py import time import redis from flask import Flask app=Flask(__name__) cache=redis.Redis(host='redis',port=6379) ​ def get_hit_count():  retries = 5  while True:   try:    return cache.incr('hits')   except redis.exceptions.ConnectionError as exc:    if retries == 0:     raise exc    retries -= 1    time.sleep(0.5) @app.route('/') def hello():  count = get_hit_count()  return 'Hello World! I have been seen {} times.\n'.format(count)

在此示例中,redis是应用程序网络上的redis容器的主机名,该主机使用的端口为6379.

在composetest目录中创建另一个名为requirements.txt的文件,内容如下:

master # vi requirements.txt flask redis

(2)创建Dockerfile文件

在composetest目录中,创建一个名为Dockerfile的文件,内容如下:

matest # vi Dockerfile FROM python:3.7-alpine WORKDIR /code ENV FLASK_APP app.py ENV FLASK_RUN_HOST 0.0.0.0 RUN apk add --no-cache gcc musl-dev linux-headers COPY requirements.txt requirements.txt RUN pip install -r requirements.txt COPY . . CMD ["flask","run"]

Dockerfile内容解释:

  • FROM python:3.7-alpine:从Python3.7镜像开始构建镜像。

  • WORKDIR /code:将工作目录设置为/code。

  • RUN apk add --no-cache gcc musl-dev linux-headers:安装gcc

  • COPY requirements.txt requirements.txt:复制requirements.txt.

  • RUN pip install -r requirements.txt:安装Python依赖项。

  • COPY . .:将 . 项目中的当前目录复制到 . 镜像中的工作目录。

  • CMD ["flask","run"]:容器提供默认执行的命令为:flask run。

(3)创建docker-compose.yml

在测试目录中创建一个名为docker-compose.yml的文件,内容如下:

master # vi docker-compose.yml version: '3' services:   web:    build: .    ports:       - "5000:5000"  redis:     image: "redis:alpine"

该Compose文件定义了两个服务:web和redis。

  • web:该web服务使用从Dockerfile当前目录中构建的镜像。然后,他将容器和主机绑定到暴露的端口5000。

  • redis:该redis服务使用redis镜像。

(4)使用Compose命令构建和运行应用

在测试目录中,执行以下命令来启动应用程序:

master # docker-compose up

如果你想在后台执行该服务可以加上-d参数:

master # docker-compose up -d

4.4compose实战

(1)使用Docker Compose部署WordPress

创建docker-comopse.yml:

master # mkdir wordpress 
master # cd wordpress/
master # vi docker-compose.yml
version: '3.3' services: db: image: mysql:5.7
volumes: - db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress: depends_on:
- db
image: wordpress:latest
ports: - "8000:80"
restart: always environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress volumes: db_data: {}

使用Compose编排部署WordPress

master # docker-compose up -d 
Creating network "wordpress_default" with the default driver
Creating volume "wordpress_db_data" with default driver
Creating wordpress_db_1 ... done
Creating wordpress_wordpress_1 ... done
master # docker-compose ps
[root@docker-compose wordpress]# docker-compose ps Name Command State Ports
-------------------------------------------------------------------------------------
wordpress_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
wordpress_wordpress_1 docker-entrypoint.sh apach ... Up 0.0.0.0:8000->80/tcp
  1. 在浏览器端通过http://IP:8000访问WordPress

  2. 配置用户信息,点击“Install WordPress”

  3. 登录WordPress

  4. 至此,使用Compose编排部署WordPress就完成了。

(2)使用Docker Compose部署Owncloud

编写docker-compose.yml

master # mkdir owncloud 
master # cd owncloud
master # vi docker-compose.yml
version: '3'
services:
owncloud:
image: owncloud
links: - mysql:mysql
volumes: - "/data/db/owncloud:/var/www/html/data"
ports: - 5679:80
mysql:
image: mysql:5.7
volumes:
- "/data/mysql/:/var/lib/mysql"
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: "123456"
MYSQL_DATABASE: ownCloud

使用Compose编排部署owncloud:

master # docker-compose up -d 
Creating network "ownclowd_default" with the default driver
Creating ownclowd_mysql_1 ... done
Creating ownclowd_owncloud_1 ... done
master # docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------------------------
ownclowd_mysql_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp, 33060/tcp
ownclowd_owncloud_1 docker-entrypoint.sh apach ... Up 0.0.0.0:5679->80/tcp
  1. 在浏览器端通过http://IP:5679访问owncloud

  2. 创建管理员账号并登录

  3. 至此,使用Compose编排部署ownCloud就完成了

你可能感兴趣的:(Linux,docker,容器,运维)