Docker概述

镜像(image):

一个只读模板。一个镜像可以用来创建多个Docker容器,好似Java中的类和对象,镜像是类,容器是对象。

容器(container):

Docker利用容器独立运行一个或一组应用,容器是用镜像创建的运行实例。
容器可以被启动、开始、停止、删除。
每个容器都是相互个隔离的。
也可以把容器看做一个简易版Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)及运行在其中的应用程序。
容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器最上面一层可读可写。

仓库(repository):

仓库是集中存放镜像文件的场所。
仓库和仓库注册服务器(registry)是有区别的,后者往往存在多个仓库,每个仓库又存在多个镜像,每个镜像有不同的标签。
仓库分为公开仓库和私有仓库两种形式。
最大的公开仓库是Docker Hub,国内最大的为阿里云、网易云等。

Docker安装

环境:CentOS 7

1.官方文档

2.yum安装gcc相关环境:

yum -y install gcc
yum -y install gcc-c++

3.卸载旧版本:

yum remove docker \
					docker-client \
					docker-client-latest \
					docker-common \
					docker-latest \
					docker-latest-logrotate \
					docker-logrotate \
					docker-engine

4.安装依赖包:

yum install -y yum-utils

5.设置镜像仓库:

# 错误
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
## 报错
[Errno 14] curl#35 - TCP connection reset by peer
[Errno 12] curl#35 - Timeout

# 推荐国内镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

6.更新yum软件包索引:

yum makecache fast

7.安装Docker CE

yum install docker-ce docker-ce-cli containerd.io

8.启动Docker

systemctl start docker

9.测试命令:

docker version # 查看Docker版本

docker run hello-world # 拉取镜像

docker images # 查看本地镜像

Docker卸载

systemctl stop docker

yum -y remove docker-ce docker-ce-cli containerd.io

rm -rf /var/lib/docker

Docker换源

# 创建或修改/etc/docker/daemon.json文件
vim /etc/docker/daemon.json
{
    "registry-mirrors": ["https://registry.docker-cn.com"]
}
systemctl daemon-reload
systemctl restart docker.service

# 网易 http://hub-mirror.c.163.com

# ustc https://docker.mirrors.ustc.edu.cn

# 中国科技大学 https://docker.mirrors.ustc.edu.cn

# 阿里云容器 服务 https://cr.console.aliyun.com/
# 首页点击“创建我的容器镜像” 得到一个专属的镜像加速地址,类似于“https://1234abcd.mirror.aliyuncs.com”

nginx安装

# 运行时报错
Cannot connect to the Docker daemon at unix:///var/run/docker.sock

# 解决方法
systemctl restart docker
docker search nginx
docker pull nginx
docker images
docker run -d --name nginx -p 3344:80 nginx
docker ps
docker stop <container-id>

tomcat安装

docker search tomcat
docker pull tomcat
docker run -it --rm tomcat:9.0
docker run -d -p 3355:8080
docker exec -it <container-id> /bin/bash

# 问题:1.部分Linux命令无法执行;2.webapps文件夹为空,文件在webapps.dist
cp -r webapps.dist/* webapps
rm webapps.dist webapps

部署es+kibana

# es暴露的端口很多,十分耗内存,数据一般需要放置到安全目录
# 启动es
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:latest
# --net somenetwork 网络配置

# 查看CPU状态
docker stats

# 运行环境修改
docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:latest

Portainer安装

Docker图形化管理工具,提供一个后台面板:

docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

Rancher(CI/CD使用)

Docker镜像讲解

镜像是什么

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

所有应用直接打包Docker镜像。

如何得到镜像:

  • 官方下载
  • 朋友分享
  • 自己制作

Docker镜像加载原理

UnionFS(联合文件系统)

我们下载的时候看见的一层层就是这个。

是一种分层、轻量级且高性能的文件系统,支持对文件系统的修改作为一次提交来层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directions into a single virtual filesystem)。Union文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

Docker镜像加载原理

Docker的镜像实际上由一层层文件系统组成,这种层级的文件系统称为UnionFS

bootfs(boot file system)主要包含bootloaderkernelbootloader主要引导加载kernelLinux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统一样,包含boot加载器和内核。boot加载完成后整个内核都在内存中,此时内存的使用权已转交给内核,此时系统也会卸载bootfs

rootfs,在bootfs之上。包含的就是典型Linux系统中的/dev/proc/bin/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,如UbuntuCentOS等。

对于一个精简的OSrootfs可以很小,只需包含最基本的命令、工具和程序库即可,因为底层直接用Hostkernel,自己只需提供rootfs。可见对于不同的Linux发行版,bootfs基本一致,rootfs会有差别,因此不同的发行版可以公用bootfs

分层理解

为什么Docker镜像采用分层结构?

资源共享,如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份Base镜像,内存中也只需加载一份Base镜像,这样就可以为所有的容器服务了,且镜像的每一层都可以被共享。

使用docker image inspect查看镜像分层。

特点

Docker镜像一般都是只读的,当容器启动时,一个新的可写层被加载到镜像顶部。

这一层就是我们常说的容器层,容器之下的都叫镜像层。

commit镜像

docker commit #提交容器成为一个新的版本

# 命令和git原理类似
docker commit -m="description" -a="author" id target_image_name:[TAG]

实战测试

docker run -it -p 8080:8080 tomcat

# 将webapps.dist所有文件拷贝到webapps
cp -r webapps.dist/* webapps

# 将修改后的容器通过commit提交为一个新的镜像
docker commit -a="dc" -m="add webapps" id name:version

容器

容器就是通过docker镜像创建的实例对象,常用命令如下:

docker ps # 查看运行中的容器状态
docker ps -a # 查看所有容器状态
docker ps -aq # 列出所有容器ID
docker stop $(docker ps -aq) # 停止所有容器
docker rm $(docker ps -aq) # 删除所有容器
docker rmi $(docker images -q) # 删除所有镜像

容器数据卷

什么是容器数据卷?

Docker的理念:将应用和环境打包成一个镜像。

如果数据都在容器中,容器一删除则数据消失。

需求:数据持久化。

容器之间需要有一个数据共享技术。

Docker容器中产生的数据同步到本地。

这就是卷技术,目录挂载,将容器内目录挂载到虚拟机或Linux中。

总结:容器的持久化和同步操作。容器间也可以数据共享。

使用数据卷

使用命令挂载

docker run -it -v 主机内目录:容器内目录

docker run -it -v /home/test_real:/home centos /bin/bash

# 宿主机查看挂载状态
docker inspect container-id

"Mounts": [
            {
                "Type": "bind",
                "Source": "/home/test_real",
                "Destination": "/home",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ]
        
# 退出容器
exit

# 修改文件内容
vim testfile

# 重新打开容器
docker start container-id

# 进入容器
docker attach container-id #未start报错:You cannot attach to a stopped container, start it first

MySQL安装

思考:MySQL数据持久化问题。

# 拉取MySQL
docker pull mysql

# 官方启动:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

# 运行容器并做数据挂载
docker run -d -p 3310:3306 -v /home/mysql_real/conf:/etc/mysql/conf.d -v /home/mysql_real/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql

具名和匿名挂载

# 匿名挂载
-v 容器内路径
docker run -d -P --name name -v /etc/nginx nginx # -P:随机映射端口

# 查看所有的volume情况
docker volume ls

# 具名挂载
docker run -d -P --name name -v juming-nginx:/etc/nginx nginx

所有Docker容器内的卷,没有指定目录的情况下都在/var/lib/docker/volumes/xxx/_data

通过具名挂载可以方便的找到我们的一个卷,大多数情况使用具名挂载

# 如何确定匿名挂载还是具名挂载,还是指定路径挂载
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载

拓展:

# 通过-v容器内路径:ro/rw改变读写权限
docker run -d -P --name name -v juming-nginx:/etc/nginx:ro nginx # 只能通过宿主机操作,容器内部无法操作
docker run -d -P --name name -v juming-nginx:/etc/nginx:rw nginx

初识Dockerfile

Dockerfile就是用来构建Docker镜像的构建文件。其实就是命令脚本,通过这个脚本可以生成镜像。

镜像是一层层的,脚本就是一个个的命令,每个命令就是一层。

# 创建一个dockerfile文件
# 指令(大写) 参数
FROM centos

VOLUME["volume01","volume02"] # 匿名挂载,和外部一定有一个同步目录

CMD echo "-----end-----"
CMD /bin/bash

# 使用
docker build -f dockerfile1 -t dc/centos .

# 查看容器本地卷信息,测试文件是否同步
docker inspect -f "{{.Monuts}}" id

这种方式使用十分多,因为我们通常会构建自己的镜像。

假设构建镜像的时候没有挂载卷,要手动镜像挂载,-v 卷名:容器内路径

数据卷容器

多个MySQL实现数据共享。

docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql

docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql

容器之间配置信息的传递,数据卷容器的生命周期一直持续到无人使用为止。

一旦持久化到了本地,这个时候本地数据不会删除。

DockerFile

核心是用来构建Docker镜像的文件。是一个命令参数脚本。

构建步骤:

  1. 编写一个Dockerfile文件
  2. docker build构建成为一个镜像
  3. docker run运行镜像
  4. docker push发布镜像(DockerHub、阿里云镜像仓库)

DockerFile构建过程

基础知识

  1. 每个保留关键字(指令)都必须为大写字母
  2. 执行顺序由上至下
  3. #为注释
  4. 每个指令都会创建提交一个新镜像层并提交

DockerFile面向开发。

DockerFile:构建文件,定义了一切的步骤,源代码。

DockerImage:通过DockerFile构建生成的镜像,最终发布和运行的产品。

Docker容器:镜像运行起来提供服务。

DockerFile指令

命令讲解
FROM构建一切的基础镜像
MAINTAINER镜像作者,name+email
RUN镜像构建时运行的命令
ADD添加服务压缩包
WORKDIR镜像工作目录
VOLUME挂载目录位置
EXPOSE保留端口配置
CMD指定容器启动时运行的命令,只有最后一条命令生效,命令可被替代
ENTRYPOINT同CMD,可以追加命令
ONBUILD当构建一个被继承DockerFile时会触发ONBUILD
COPY类似ADD,将文件拷贝到镜像中
ENV构建时设置环境变量

实战centos部署

DockerHub大部分镜像都是由基础镜像scratch组成,然后配置需要的软件和配置。

# 1.编写DockerFile文件
FROM centos

MAINTAINER dc<[email protected]>

ENV MYPATH /usr/local

WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "-----end-----"
CMD /bin/bash

# 2.通过文件构建镜像
docker build -f mydockerfile -t mycentos:1.0 .
# 运行结果
Successfully built b8fab89ecdea
Successfully tagged mycentos:1.0

# 3.测试运行
docker run -it mycentos:1.0
# 列出本地进行的变更历史
docker history image-id

CMD 和 ENTRYPOINT 的区别

CMD					# 指定容器启动时要运行的命令,只有最后一个生效,且可被替代
ENTRYPOINT			# 同CMD,可以追加命令

测试CMD

# 编写DockerFile文件
vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

# 构建镜像
docker build -f dockerfile-cmd-test -t cmd-test .

# RUN运行,发现`ls -a`命令生效
docker run `id`

# 想追加一个命令 ls -al
docker run `id` -l # error

# cmd清理 -l 替换了CMD ["ls","-a"]命令,-l不是命令所以报错

测试ENTRYPOINT

# 编写DockerFile文件
vim dockerfile-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]

# 构建镜像
docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .

DockerFile中很多命令都相似,我们需要了解其中的区别,最好的学习就是对比并测试。

实战tomcat部署

  1. 准备镜像文件,tomcat压缩包,jdk压缩包
  2. 编写DockerFile文件,官方命名Dockerfilebuild会自动寻找这个文件,不需要-f指定:
FROM centos

MAINTAINER dc<[email protected]>

COPY readme.txt /usr/local/readme.txt

ADD apache-tomcat-9.0.22.tar.gz /usr/local
ADD jdk-8u281-linux-x64.tar.gz /usr/local

RUN yum -y install vim

ENV MYPATH /usr/local

WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk-8u281
ENV CLASS_PATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.22
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.22
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out

3.构建镜像:

docker build -t diy-tomcat .

4.启动镜像:

docker run -d -p 9090:8080 --name dc-tomcat -v /home/tomcat/test:/url/local/apache-tomcat-9.0.22/webapps/test -v /home/tomcat/tomcat-logs/:/usr/local/apache-tomcat-9.0.22/logs diy-tomcat

5.进入容器:

docker exec -it `随意复制一段id` /bin/bash

6.访问测试:

curl localhost:9090

7.发布项目(做了卷挂载,直接在本地发布即可)

xml文件
jsp文件

项目部署成功。

发布镜像

DockerHub

1.登录DockerHubDocker Hub

docker login -u username -p password

2.在服务器上提交镜像:

docker tag [image-id/image-name:tag] new-image-name:tag
docker push image-id:tag/image-name:tag

aliyun镜像

1.登录阿里云:阿里云-上云就上阿里云 (aliyun.com)

2.进入容器镜像服务:容器镜像服务_镜像构建_镜像授权_镜像托管-阿里云 (aliyun.com)

3.创建命名空间

4.创建容器镜像

5.参考官方文档

Docker网络

Docker0

问题:docker是如何处理容器网络访问的?

我们首先创建一个tomcat容器,利用学到的两类方法来试试。

方式一,手动执行

docker run -d -P --name tomcat-01 tomcat
docker exec -it tomcat-01 ip addr

方式二,编写DockerFile

# DockerFile内容
FROM tomcat

MAINTAINER dc<[email protected]>

CMD docker run -d -P --name tomcat-01 tomcat
CMD docker exec -it tomcat-01 ip addr

# 构建镜像
docker build -f dockerfile -t tomcat-test .

方法有误,稍后修改。

容器启动的时候会得到一个docker分配的eth@if262ip地址。

测试:Linuxping通容器内部ip地址。

原理

每安装并启动一个Docker容器,Docker就会给其分配一个ip,只要安装了Docker,就会有一个docker0网卡。

docker0网卡使用桥接模式,使用veth-pair技术。

再启动一个容器就会多一对网卡。

7: veth4f1ae6f@if6
docker exec -it tomcat-02 ping `ip` #tomcat-02可以ping通tomcat-01
# 容器之间可以互通

小结

Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥。

Docker中所有的网络接口都是虚拟的,转发效率高。

容器删除,则对应的一对网桥也被回收。

思考场景

编写了一个微服务,database url=ip:,项目不重启,数据库ip换掉,如何进行处理?

docker exec -it tomcat-02 ping tomcat-01 # 无法直接ping通

# 启动一个tomcat-03,并与tomcat-02连接
docker run -d -P --name tomcat-03 --link tomcat-02 tomcat
# 实现通过名称ping通,但是反向无法ping通
# 其实就是tomcat-03在本地配置了tomcat-02

# 查看tomcat-03 hosts配置
docker exec -it tomcat-03 cat /etc/hosts

--link就是在hosts配置中增加了一个映射,已经不建议使用。

docker0问题:不支持容器名进行连接访问。

自定义网络

# 查看所有docker网络
docker network ls

网络模式

参数说明
bridge桥接模式
none不配置网络
host和主机共享网络
container容器网络连通(局限很大,实际使用较少)
# --net bridge 为默认参数
docker run -d -P --name tomcat-01 --net bridge tomcat

# docker0特点:默认不能通过名称访问,通过 --link 打通连接
# 可以自定义一个网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

# 查看网络概览
docker network ls

# 查看详细信息
docker network inspect mynet

# 使用自己的网络
docker run -d -P --name tomcat-mynet-01 --net mynet tomcat
docker run -d -P --name tomcat-mynet-02 --net mynet tomcat

# ping测试
docker exec -it tomcat-mynet-01 ping tomcat-mynet-02
# 两者互相可ping通

优点

redismysql:不同集群使用不同网络,保证集群是安全和健康的。

网络连通

# 启动两个容器
docker run -d -P --name tomcat-01 tomcat
docker run -d -P --name tomcat-02 tomcat

# 已知tomcat-01与tomcat-02无法ping通
# 连接网络
docker network connect mynet tomcat-01
docker network connect mynet tomcat-02

# 查看 mynet
docker network inspect mynet
# 其中包含了tomcat-01与tomcat-02
# 四个容器完美ping通

实战Redis集群部署

# 使用脚本部署
docker network create redis --subnet 172.42.0.0/16

# 通过脚本创建六个redis配置
for port in $(seq 1 6);
do
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.42.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port}
-v /mydata/redis/node-${port}/data:/data
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.42.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf;

# 1-6依次修改即可
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.42.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

# 进入容器
docker exec -it redis-1 /bin/sh # redis中为sh

# 创建集群
redis-cli --cluster create 172.42.0.11:6379 172.42.0.12:6379 172.42.0.13:6379 172.42.0.14:6379 172.42.0.15:6379 172.42.0.16:6379 --cluster-replicas 1

# 查看集群数量
redis-cli -c
cluster info
cluster nodes
set a b
get a # 第一次get会提示`Could not connect to Redis at 172.42.0.13:6379: Host is unreachable`
# 重新进入
redis-cli -c
get a 
# `Redirected to slot [15495] located at 172.42.0.14:6379
"b"`

cluster nodes
`redis-3状态为master,fail,redis-4状态为myself,master`

SpringBoot微服务打包Docker镜像

  1. 构建SpringBoot项目
  2. 打包应用
  3. 编写DockerFile
  4. 构建镜像
  5. 发布运行
# DockerFile
FROM java:8

COPY *.jar /app.jar

CMD ["--server.port=8080"]

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]

# 构建
docker build -t image-name .

Docker Compose

概述

官方概述:Overview of Docker Compose | Docker Documentation

轻松高效管理容器,定义运行多个容器。

一键启动/停止服务。

三步骤

1.Define your app’s environment with a Dockerfile so it can be reproduced anywhere.

  • Dockerfile 保证我们的项目在任何地方可以运行

2.Define the services that make up your app in docker-compose.yml so they can be run together in an isolated environment.

  • services 什么是服务
  • docker-compose.yml 文件应该怎么写

3.Run docker-compose up and Compose starts and runs your entire app.

  • 启动项目

作用:批量容器编排

理解

Compose Docker 官方开源项目,需要安装。

Dockerfile让程序在任何地方运行。

version: '2.0'
services:
	web:
		build: .
		ports:
		- "5000:5000"
		volumes:
		- .:/code
		- logvolume01:/var/log
		links:
		- redis
	redis:
		image: redis
volumes:
	logvolume01: {}

docker-compose up 100个服务

Compose重要的两个概念

  • 服务 services,容器、应用(web、redis、mysql…)
  • 项目 project,一组关联容器

安装Docker Compose

官方安装文档:Install Docker Compose | Docker Documentation

1.下载

# 官方下载,从GitHub下载,巨慢
sudo curl -L "https://github.com/docker/compose/releases/download/1.28.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 国内镜像
curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

# 查看是否下载成功
cd /usr/local/bin
ls

2.授权

chmod +x /usr/local/bin/docker-compose
# 或
chmod 777 /usr/local/bin/docker-compose

# 任意位置运行 docerk-compose version 查看是否成功

初使用

使用教程:Get started with Docker Compose | Docker Documentation

1.创建项目文件夹

2.项目文件夹下创建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)

3.创建requirements.txt依赖包文件

4.创建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						# 使用pip安装
EXPOSE 5000												# 暴露端口
COPY . .												# 拷贝当前目录
CMD ["flask", "run"]									# 运行

5.在Compose文件中定义服务:

# 以前我们需要docker run逐个运行
# 现在创建docker-compose.yml文件
version: "3.9"					# 版本
services:						# 服务
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

6.使用Compose构建并运行应用:

docker-compose up # docker-compose up -d 后台运行
# 我这里报错了,报错如下:
ERROR: Version in "./docker-compose.yml" is unsupported. You might be seeing this error because you're using the wrong Compose file version. Either specify a supported version (e.g "2.2" or "3.3") and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.
For more on the Compose file format versions, see https://docs.docker.com/compose/compose-file/

# 解决方案,修改docker-compose.yml文件中的版本
version: "3.9"  ->  version: "3.3"

# 项目部署过程中出现了其它错误
docker-compose build # 先build一下
docker-compose up # 成功启动

# 测试,每访问一次计数器+1
localhost:5000 # 浏览器键入
curl localhost:5000 # curl请求

7.停止:

# 在yaml文件所在目录下运行命令
docker-compose stop
Ctrl+C

流程:

1.创建网络

2.执行Docker-compose.yml

3.启动服务

默认规则:

自动拉取镜像:

[root@localhost ~]# docker service ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.

**命名规则:**默认服务名 文件名_服务名_num。A B _num 副本数量。集群状态下不可能只有一个运行实例。弹性:10 HA 高可用、高并发。kunectl service负载均衡。

**网络规则:**使用命令docker network ls查看,默认名称composetest_default。项目中的内容都在同一网络,可通过域名访问。

小结:

1.应用,如app.py

2.Dockerfile应用打包为镜像

3.Docker-compose.yml文件(定义整个服务、需要的环境)。完整的上线服务

4.启动compose项目(docker-compose up)

yaml规则

官方示例:Compose file version 3 reference | Docker Documentation

docker-compose.yml是核心。

# 只有三层

version: '' # 版本
services: # 服务
	服务1: web
		# 服务配置
		images
		build
		network
		...
	服务2: redis
	...
# 其他配置 网络/卷/全局规则
volumes:
networks:
configs:

depends_on

Simple example:

version: "3.9"
services:
  web:
    build: .
    depends_on:			# 依赖于db和redis
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres
# 启动顺序:web --> redis --> db

There are several things to be aware of when using depends_on:

  • depends_on does not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.
  • Version 3 no longer supports the condition form of depends_on.
  • The depends_on option is ignored when deploying a stack in swarm mode with a version 3 Compose file.

deploy

Added in version 3 file format.

Specify configuration related to the deployment and running of services. This only takes effect when deploying to a swarm with docker stack deploy, and is ignored by docker-compose up and docker-compose run.

version: "3.9"
services:
  redis:
    image: redis:alpine
    deploy:
      replicas: 6					# 副本
      placement:
        max_replicas_per_node: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

部署wp博客

官方文档部署WordPress博客:Quickstart: Compose and WordPress | Docker Documentation

1.创建一个空文件夹,此处命名为my_wordpress

mkdir my_wordpress

2.切换到对应目录

cd my_wordpress/

3.创建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: {}

Notes:

  • The docker volume db_data persists any updates made by WordPress to the database. Learn more about docker volumes
  • WordPress Multisite works only on ports 80 and 443.

4.构建项目

Now, run docker-compose up -d from your project directory.

This runs docker-compose up in detached mode, pulls the needed Docker images, and starts the wordpress and database containers.

$ docker-compose up -d

Note: WordPress Multisite works only on ports 80 and/or 443. If you get an error message about binding 0.0.0.0 to port 80 or 443 (depending on which one you specified), it is likely that the port you configured for WordPress is already in use by another service.

5.开始安装

经过第4步后,访问localhost:8000端口即可设置博客。

实战

1.编写项目微服务

2.Dockefile构建镜像

3.docker-compose.yaml编排项目

4.docker-compose up

5.docker-compose up --build项目重新部署打包

Docker Swarm

Docker Swarm官方文档:Swarm mode overview | Docker Documentation

节点如何工作:

Docker Engine 1.12 introduces swarm mode that enables you to create a cluster of one or more Docker Engines called a swarm. A swarm consists of one or more nodes: physical or virtual machines running Docker Engine 1.12 or later in swarm mode.

There are two types of nodes: managers and workers.

Swarm mode cluster

If you haven’t already, read through the swarm mode overview and key concepts.

管理与工作节点

管理节点

Manager nodes handle cluster management tasks:

Using a Raft implementation, the managers maintain a consistent internal state of the entire swarm and all the services running on it. For testing purposes it is OK to run a swarm with a single manager. If the manager in a single-manager swarm fails, your services continue to run, but you need to create a new cluster to recover.

To take advantage of swarm mode’s fault-tolerance features, Docker recommends you implement an odd number of nodes according to your organization’s high-availability requirements. When you have multiple managers you can recover from the failure of a manager node without downtime.

  • A three-manager swarm tolerates a maximum loss of one manager.

  • A five-manager swarm tolerates a maximum simultaneous loss of two manager nodes.

  • An N manager cluster tolerates the loss of at most (N-1)/2 managers.

  • Docker recommends a maximum of seven manager nodes for a swarm.

    Important Note: Adding more managers does NOT mean increased scalability or higher performance. In general, the opposite is true.

工作节点

Worker nodes are also instances of Docker Engine whose sole purpose is to execute containers. Worker nodes don’t participate in the Raft distributed state, make scheduling decisions, or serve the swarm mode HTTP API.

You can create a swarm of one manager node, but you cannot have a worker node without at least one manager node. By default, all managers are also workers. In a single manager node cluster, you can run commands like docker service create and the scheduler places all tasks on the local Engine.

To prevent the scheduler from placing tasks on a manager node in a multi-node swarm, set the availability for the manager node to Drain. The scheduler gracefully stops tasks on nodes in Drain mode and schedules the tasks on an Active node. The scheduler does not assign new tasks to nodes with Drain availability.

Refer to the docker node update command line reference to see how to change node availability.

Raft

图中有一个Raft Consensus Group的概念,我们来查阅一下资料。

Raft:一种新的分布式协议研究,为真实世界应用建立的协议,主要注重协议落地性和可理解性。保证大多数节点存活才可使用。

关于分布式系统的Raft算法讲解:分布式系统的Raft算法 - 解道Jdon

Raft算法详解:图解:什么是Raft算法? - 无敌码龙的个人空间 - OSCHINA - 中文开源技术交流社区

命令

# 帮助命令
docker swarm --help

Usage:  docker swarm COMMAND

Manage Swarm

Commands:
  ca          Display and rotate the root CA
  init        Initialize a swarm
  join        Join a swarm as a node and/or manager
  join-token  Manage join tokens
  leave       Leave the swarm
  unlock      Unlock swarm
  unlock-key  Manage the unlock key
  update      Update the swarm
  
docker swarm init			# 初始化节点
docker swarm join			# 加入节点
# 获取令牌
docker swarm join-token manager
docker swarm join-token worker
docker node ls 				# 查看节点

具体使用

服务无感升级为灰度发布(也称金丝雀发布)。

docker run														# 容器启动,不具有扩缩容功能
docker service 服务											   # 能实现扩缩容及滚动更新
docker service create -p 8888:80 --name my-nginx nginx
# 查看服务
docker service ps my-nginx
docker service ls
docker service inspect my-nginx
# 创建副本
docker service update --replicas 3 my-nginx
docker service update --replicas 1 my-nginx 				    # 更新为1个服务
docker service scale my-nginx=5									# 动态扩缩容,与update效果相同
docker service rm my-nginx

概念总结

Swarm

集群的管理和编号。docker可以初始化一个swarm集群,其它节点可以加入。(manager、worker)

Node

就是一个docker节点,多个节点组成一个网络集群。

Service

任务,可以在managerworker来运行。用户访问的其实就是service,这是集群的核心。

Task

容器内命令,细节任务。

调整service运行方式

docker service create --mode replicated --name my-centos centos			# 仅在副本运行
docker service create --mode global --name haha alpine ping baidu.com	# 全局运行

拓展

网络模式:“PublishMode”:“ingress”

Swarm:

Overlay:网络变成一个整体

ingress:具有负载均衡功能的特殊Overlay网络,

Docker Stack

docker-compose			# 单机部署项目
docker-compose up -d wordpress.yaml 
docker stack			# 集群部署
docker stack deploy wordpress.yaml

Docker Secret

Commands:
  create      Create a secret from a file or STDIN as content
  inspect     Display detailed information on one or more secrets
  ls          List secrets
  rm          Remove one or more secrets

Docker Config

Commands:
  create      Create a config from a file or STDIN
  inspect     Display detailed information on one or more configs
  ls          List configs
  rm          Remove one or more configs

文章许可:本文采用CC BY-NC-SA 4.0许可协议,转载请注明出处。