Docker入门与进阶(基础+实战+进阶+Compose+Swarm)超详细版

一、Docker入门

1.1 Docker 概述

Docker 是一个开源的轻量级的应用容器引擎

应用场景

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。

Docker和虚拟机的对比

  • 传统虚拟机,虚拟出硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件。
  • Docker内的容器直接运行在宿主机内,容器是没有自己的内核的,也没有虚拟硬件。每个容器都是相互隔离的,每个容器都有属于自己的文件系统,互不影响。

容器化的好处

  • 应用更快速的交付和部署
  • 更便捷的升级和扩展
  • 更简单的系统运维
  • 更高效的资源利用

Docker的组成 仓库、镜像和容器
在这里插入图片描述

  • 镜像

Docker镜像里包含了已打包的应用程序及其所依赖的环境。类似于Win的程序安装包。

  • 镜像仓库

Docker镜像仓库用于存放Docker镜像,以及促进不同人和不同电脑之间共享这些镜像。类似于Win放安装包的仓库。

  • 容器

Docker容器通常是一个Linux容器,它基于Docker镜像被创建。一个运行中的容器是一个运行在Docker主机上的进程。类似于Win安装好的程序。

1.2 Docker 安装、配置、卸载

Docker的安装步骤

0.删除旧版本,可以避免出现安装失败的情况

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

1.安装docker,-y表示不询问安装,直到安装成功

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

2.启动docker,并查看版本信息

systemctl start docker
docker version

在这里插入图片描述

3.配置国内镜像仓库

vim /etc/docker/daemon.json
{
    "registry-mirrors": [
        "https://registry.docker-cn.com"
    ]
}

配置完成后需重启docker服务

systemctl restart docker  # 重启docker服务
systemctl status docker  # 确认docker服务正常运行

4.将docker设置为开机启动

systemctl enable docker

5.卸载Docker

# 1. 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 2. 删除资源  . /var/lib/docker是docker的默认工作路径
rm -rf /var/lib/docker

1.3 Docker 使用流程

在这里插入图片描述

1.4 Docker 访问原理

Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问!Docker Server接收到Docker-Client的指令,就会执行这个指令!
在这里插入图片描述

1.5 Docker 常用命令

Docker命令的官方地址

1.5.1 基础命令

docker version # 查看docker的版本信息
docker info # 查看docker的系统信息,包括镜像和容器的数量
docker 命令 --help # 帮助命令(可查看可选的参数)

1.5.2 镜像命令

docker images查看本地所有镜像

[root@localhost ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   6 months ago   13.3kB
# 解释:
1.REPOSITORY  镜像的仓库源
2.TAG  镜像的标签
3.IMAGE ID 镜像的id
4.CREATED 镜像的创建时间
5.SIZE 镜像的大小

# 可选参数
-a/--all 列出所有镜像
-q/--quiet 只显示镜像的id

docker search 搜索镜像

[root@localhost ~]# docker search mysql
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   10308     [OK]
mariadb                           MariaDB is a community-developed fork of MyS…   3819      [OK]
mysql/mysql-server                Optimized MySQL Server Docker images. Create…   754                  [OK]
percona                           Percona Server is a fork of the MySQL relati…   517       [OK]
centos/mysql-57-centos7           MySQL 5.7 SQL database server                   86
mysql/mysql-cluster               Experimental MySQL Cluster Docker images. Cr…   79
centurylink/mysql                 Image containing mysql. Optimized to be link…   60                   [OK]

# 可选参数
Options:
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output
      
      
# 搜索收藏数大于3000的镜像
[root@localhost ~]# docker search mysql --filter=STARS=3000
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   10308     [OK]
mariadb   MariaDB is a community-developed fordockerk of MyS…   3819      [OK]

docker pull 镜像名[:tag] 下载镜像

分层下载,docker image的核心-联合文件系统(UnionFS)

# 如果不写tag默认就是下载最新版 latest
docker pull mysql	
# 指定版本下载
docker pull mysql:5.7

docker rmi 删除镜像

# 1.删除指定的镜像id
docker rmi -f 镜像id
# 2.删除多个镜像id
docker rmi -f 镜像id 镜像id 镜像id
# 3.删除全部的镜像id
docker rmi -f $(docker images -aq)

1.5.3 容器命令

容器是基于Docker镜像被创建的。

# 先拉取一个centos镜像
docker pull centos

docker run [Options] image运行容器

docker run [Options] image

#参数说明
--name="名字"           指定容器名字
-d                     后台方式运行
-it                    使用交互方式运行,进入容器查看内容
-p                     指定容器的端口
	-p ip:主机端口:容器端口  配置主机端口映射到容器端口
	-p 主机端口:容器端口(常用)
	-p 容器端口
-P                     随机指定端口
-e					   环境设置
-v					   容器数据卷挂载

运行并进入容器centos

[root@localhost ~]# docker run -it centos /bin/bash
[root@ce2bbae9f151 /]# ls
bin  etc   lib	  lost+found  mnt  proc  run   srv  tmp  var
dev  home  lib64  media       opt  root  sbin  sys  usr

退出容器

exit 	# 停止容器并退出(后台方式运行则仅退出)
Ctrl+P+Q  # 不停止容器退出

docker ps 查看运行的容器

# 查看当前正在运行的容器
docker ps 
     
-a   # 查看所有容器的运行记录
-n=? # 显示最近创建的n个容器
-q   # 只显示容器的id

docker start 容器id 启动容器

docker start 容器id          # 启动容器
docker restart 容器id        # 重启容器
docker stop 容器id           # 停止当前运行的容器
docker kill 容器id           # 强制停止当前容器

1.5.4 其他常用命令

docker logs查看日志

docker logs -tf 容器id
docker logs --tail num 容器id  # num为要显示的日志条数

docker top查看容器中进程信息

docker top 容器id

docker inspect查看容器的元数据

docker inspect 容器id

进入容器,因为通常我们的容器都是使用后台方式来运行的,有时需要进入容器修改配置

  • docker exec
# docker exec 进入容器后开启一个新的终端,可以在里面操作
docker exec -it 容器id /bin/bash
  • docker attach
# docker attach 进入容器正在执行的终端
docker attach 容器id

docker cp拷贝操作

# 拷贝容器的文件到宿主机中
docker cp 容器id:容器内路径  宿主机路径

# 拷贝宿主机的文件到容器中
docker cp 宿主机路径 容器id:容器内路径

# 注意:源文件在哪就在哪进行复制操作
# 在主机中创建test.txt文件,并复制到centos容器的/home路径下
touch test.txt
docker cp /home/test.txt 08d1f5d4e7b1:/home/

1.5.5 镜像导出、导入

1. 使用export和import

这两个命令是通过容器来导出、导入镜像

docker export 容器id > xxx.tar [路径]
docker import [- 镜像名] < xxx.tar

2. 使用save和load

这两个命令是通过镜像来导出、导入镜像

docker save 镜像id > xxx.tar [路径]
docker load < xxx.tar

1.6 制作Docker镜像

Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统是UnionFS联合文件系统。
可以使用docker image inspect查看镜像的元数据

docker image inspect nginx:latest

# 镜像的分层信息 ,层级文件可以共享
"RootFS": {
    "Type": "layers",
    "Layers": [
        "sha256:87c8a1d8f54f3aa4e05569e8919397b65056aa71cdf48b7f061432c98475eee9",
        "sha256:5c4e5adc71a82a96f02632433de31c998c5a9e2fccdcbaee780ae83158fac4fa",
        "sha256:7d2b207c26790f693ab1942bbe26af8e2b6a14248969e542416155a912fec30d",
        "sha256:2c7498eef94aef8c40d106f3e42f7da62b3eee8fd36012bf7379becc4cd639a2",
        "sha256:4eaf0ea085df254fd5d2beba4e2c11db70a620dfa411a8ad44149e26428caee4"
    ]
}

镜像的特点

  • 所有的Docker镜像都起始于一个基础镜像层,当进行增加或修改内容时,会在当前镜像层之上,创建新的镜像层。
  • Docker镜像都是只读的,当容器启动时,一个新的可写层(容器层)被加载到镜像的顶部。

提交镜像 docker commit

# 使用docker commit 命令提交容器成为一个新的镜像版本
docker commit -m=“提交的描述信息”  -a="作者" 容器id 目标镜像名:[TAG] 

默认的Tomcat镜像的webapps文件夹中没有任何内容,需要从webapps.dist中拷贝文件到webapps文件夹。下面自行制作镜像:就是从webapps.dist中拷贝文件到webapps文件夹下,并提交该镜像作为一个新的镜像。使得该镜像默认的webapps文件夹下就有文件。

# 1.复制项目到webapps下
[root@localhost ~]# docker run -it tomcat /bin/bash
root@3762239532cf:/usr/local/tomcat# cd webapps
root@3762239532cf:/usr/local/tomcat/webapps# ls
root@3762239532cf:/usr/local/tomcat/webapps# cp -r ../webapps.dist/* .
root@3762239532cf:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager
# 2.项目访问 http://192.168.0.105:8080/
# 3.提交容器作为一个新的镜像
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND             CREATED         STATUS         PORTS                                       NAMES
41d0b9c0da0e   tomcat    "catalina.sh run"   4 minutes ago   Up 4 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   agitated_mccarthy
[root@localhost ~]# docker commit -m="add webapps" -a="buckletime" 41d0b9c0da0e mytomcat:1.0
sha256:6bbddb87eb6f909f77c6f851b25edd5a02ad9632f397b68f65f4169b9874f02a
# 4.查看镜像列表
[root@localhost ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
mytomcat     1.0       6bbddb87eb6f   31 seconds ago   684MB
tomcat       latest    fb5657adc892   3 months ago     680MB
centos       latest    5d0da3dc9764   6 months ago     231MB
# 5.运行新的容器并查看文件
[root@localhost ~]# docker run -it mytomcat:1.0 /bin/bash
root@5c04b86e6369:/usr/local/tomcat# ls webapps
ROOT  docs  examples  host-manager  manager

二、容器数据卷

2.1 数据卷介绍

Docker将运用与运行的环境打包形成容器运行, Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来, 那么当容器删除后,数据自然也就没有了。 为了能保存数据在Docker中我们使用卷。|

卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但卷不属于联合文件系统(Union FileSystem),因此能够绕过联合文件系统提供一些用于持续存储或共享数据的特性:。

卷的设计目的就是 数据的持久化和同步,容器间可以数据共享

数据卷的特点:

  • 数据卷可在容器之间共享或重用数据
  • 卷中的更改可以直接生效
  • 数据卷中的更改不会包含在镜像的更新中

2.2 数据卷使用

运行容器,指定挂载数据卷命令:

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

# 1.运行centos容器,并指定挂载数据卷
[root@localhost ~]# docker run -it -v /home/main_data/:/home/docker_data centos /bin/bash
# 2.使用docker inspect查看容器的元数据,查看是否挂载成功
[root@localhost ~]# docker inspect 9f80a90b6c54
"Mounts": [
            {
                "Type": "bind",
                "Source": "/home/main_data",
                "Destination": "/home/docker_data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ]
# 3.在主机中创建文件
[root@localhost main_data]# touch main.txt
[root@localhost main_data]# ls
main.txt
# 4.查看容器中的文件
[root@9f80a90b6c54 /]# ls /home/docker_data/
main.txt

示例:MySQL容器建立数据卷同步数据

在Linux下的MySQL默认的数据文档存储目录为/var/lib/mysql,默认的配置文件的置/etc/mysql/conf.d,为了避免MySQL镜像或容器删除后,造成的数据丢失,下面建立数据卷保存MySQL的数据和文件。

# 1.启动mysql  挂载数据卷
docker run -d -p 3306:3306 \
		   -v /home/mysql/conf:/etc/mysql/conf.d \
		   -v /home/mysql/data:/var/lib/mysql \
		   -e MYSQL_ROOT_PASSWORD=123456 mysql 
# 2.远程连接mysql服务,若无权限,进入mysql容器中修改远程连接权限
docker exec -ti 36d4806c765a /bin/bash
# 登录mysql
mysql -u root -p
# 修改root 可以通过任何客户端连接
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
# 3.使用客户端创建mytest数据库并查看主机中同步的数据,数据同步成功
[root@localhost data]# ls /home/mysql/data

2.3 docker volume 命令

[root@localhost data]# docker volume --help

Commands:
  create      # 创建数据卷
  inspect     # 查看数据卷详情
  ls          # 查看所有数据卷列表
  prune       # 删除所有未使用的卷
  rm          # 删除数据卷

docker volume create 创建数据卷

[root@localhost data]# docker volume create my-vol

docker volume ls 查看所有数据卷列表

[root@localhost data]# docker volume ls

docker volume inspect 查看数据卷详情

[root@localhost data]# docker volume inspect my-vol 
[
    {
        "CreatedAt": "2022-04-07T12:52:42+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

docker volume rm 删除数据卷

[root@localhost data]# docker volume rm my-vol

docker volume prune 删除所有未使用的卷

[root@localhost data]# docker volume prune

docker rm -v 删除容器时也删除相关的卷

2.4 具名挂载和匿名挂载

匿名挂载

匿名挂载就是在指定数据卷的时候,只指定容器路径,不指定对应的主机路径,这样对应映射的主机路径就是默认的路径/var/lib/docker/volumes/中自动生成一个随机命名的文件夹

# 运行并匿名挂载Nginx容器
[root@localhost data]# docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看卷列表
[root@localhost data]# docker volume ls
DRIVER    VOLUME NAME
local     0e102dae2f6731494400f7c98c11c835293c030b736588d80d4296b96f10c71d
local     my-vol

具名挂载

具名挂载,就是指定文件夹名称,区别于指定路径挂载,这里的指定文件夹名称是在Docker指定的也是默认数据卷路径下的。通过docker volume ls命令可以查看当前数据卷的目录情况。

# 运行并具名挂载Nginx容器
[root@localhost data]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
# 查看卷列表
[root@localhost data]# docker volume ls
DRIVER    VOLUME NAME
local     0e102dae2f6731494400f7c98c11c835293c030b736588d80d4296b96f10c71d
local     juming-nginx
local     my-vol
# 查看数据卷详情,注意主机路径也是默认数据卷路径下
[root@localhost data]# docker volume inspect juming-nginx
[
    {
        "CreatedAt": "2022-04-07T13:10:39+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
        "Name": "juming-nginx",
        "Options": null,
        "Scope": "local"
    }
]

匿名挂载,具名挂载,指定路径挂载的命令区别如下:

  • 匿名挂载 -v 容器内路径 ,不建议使用
  • 具名挂载 -v 卷名:容器内路径
  • 指定路径挂载 -v 宿主机路径:容器内路径

扩展:指定数据卷映射的相关参数:ro / rw

  • ro —— readonly 只读。设置了只读则说明此路径只能通过宿主机来操作,不能通过容器操作
  • rw ----- readwrite 可读可写
[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
[root@localhost ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx

2.5 数据卷之Dockerfile

Dockerfile 是一个构建docker镜像的构建文件,是一个命令脚本文件。通过这个脚本可以生成镜像。

可以在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷。

dockerfile脚本

# 脚本中指令(大写)
# 基础镜像
FROM centos
# 匿名挂载
VOLUME ["volume01","volume02"]
CMD echo "----end----"
# 命令行环境
CMD /bin/bash

执行脚本构建镜像 docker build

[root@localhost docker_test_volume]# docker build -f dockerfile1 -t buckletime-centos:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 5d0da3dc9764
Step 2/4 : VOLUME ["volume01","volume02"]
 ---> Running in 0af875dd3c35
Removing intermediate container 0af875dd3c35
 ---> 3876cf15e836
Step 3/4 : CMD echo "----end----"
 ---> Running in 73344c7d325a
Removing intermediate container 73344c7d325a
 ---> ce432169d4d9
Step 4/4 : CMD /bin/bash
 ---> Running in 8e12aeb63375
Removing intermediate container 8e12aeb63375
 ---> b74eed3e6de1
Successfully built b74eed3e6de1
Successfully tagged buckletime-centos:1.0
# 查看镜像
[root@localhost docker_test_volume]# docker images
REPOSITORY          TAG       IMAGE ID       CREATED          SIZE
buckletime-centos   1.0       b74eed3e6de1   15 seconds ago   231MB
mytomcat            1.0       6bbddb87eb6f   3 hours ago      684MB
nginx               latest    12766a6745ee   8 days ago       142MB
tomcat              latest    fb5657adc892   3 months ago     680MB
mysql               latest    3218b38490ce   3 months ago     516MB
centos              latest    5d0da3dc9764   6 months ago     231MB

查看数据卷

# 启动自己构建的镜像并进入容器
[root@localhost docker_test_volume]# docker run -it b74eed3e6de1 /bin/bash
# 查看目录
[root@20978f76e318 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02
# 查看数据卷挂载信息
[root@localhost docker_test_volume]# docker inspect 20978f76e318
"Mounts": [
    {
        "Type": "volume",
        "Name": "9bdb13dbdd9a543a00b01e6a84475c6877547a5b722617d1f2afa0546f5cbb47",
        "Source": "/var/lib/docker/volumes/9bdb13dbdd9a543a00b01e6a84475c6877547a5b722617d1f2afa0546f5cbb47/_data",
        "Destination": "volume01",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    },
    {
        "Type": "volume",
        "Name": "2edc8939b90a1a6f3b684a279819b7f0f20fd89f9eebc9a78a4318fb77cf22ba",
        "Source": "/var/lib/docker/volumes/2edc8939b90a1a6f3b684a279819b7f0f20fd89f9eebc9a78a4318fb77cf22ba/_data",
        "Destination": "volume02",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

可以看到Mounts下有宿主机的挂载目录。因为dockerfile中没有指定宿主机目录,所以属于匿名挂载,在/var/lib/docker/volumes/目录下生成了随机命名的路径。

2.6 数据卷容器

容器数据卷是指建立数据卷,来同步多个容器间的数据,实现容器间的数据同步。

在这里插入图片描述
首先启动容器1,volume01、volume02为挂载目录

docker run -it --name cnetos01 buckletime-centos:1.0

然后启动容器2,通过参数--volumes-from,设置容器2和容器1建立数据卷挂载关系

docker run -it --name centos02 --volumes-from cnetos01 buckletime-centos:1.0

数据卷容器总结:

  • 容器之间配置文件和数据的同步,数据卷容器的生命周期一直持续到没有容器使用为止
  • 如果使用-v 持久化到主机中,主机中的数据不会被删除,永久有效。

三、Dockerfile

3.1 Dockerfile 介绍

Dockerfile 是一个构建docker镜像的构建文件,是一个命令脚本文件。通过这个脚本可以生成镜像。

构建步骤

  1. 编写dockerfile文件
  2. docker build 构建镜像
  3. docker run 运行镜像
  4. docker push 发布镜像

Dockerfile 基础知识点

  • 指令必须是大写
  • 指令从上到下顺序执行
  • # 表示注释
  • 每个指令都会创建并提交一个新的镜像层
    在这里插入图片描述

3.2 Dockerfile 指令

FROM 基础镜像,一切从这里构建
MAINTAINER 镜像维护者描述,姓名+邮箱
RUN 镜像构建的时候需要运行的命令
COPY 将文件复制到目标镜像中
ADD 添加文件到目标镜像中,支持使用tar文件和URL路径
WORKDIR 指定镜像的工作目录
VOLUME 挂载的目录,只能指定容器内的路径,宿主机的路径为默认挂载目录
EXPOSE 指定容器对外暴露的端口
CMD 指定启动容器时要运行的命令,只有最后一个命令会生效,可以被替代
ENTRYPOINT 类似CMD,可以追加命令
ENV 构建的时候设置环境变量

3.3 Dockerfile 实战

实战1:基于官方centos镜像构建定制化centos

官方的centos镜像是最小使用版本,缺失很多命令。我们可以基于官方centos镜像定制化一个contos

1.编写dockerfile文件 dockerfile-mycentos

FROM centos:7
MAINTAINER buckletime<[email protected]>

ENV MYPATH /usr/local
WORKDIR $MYPATH

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

EXPOSE 80

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

2.通过dockerfile文件构建镜像

docker build -f Dockfile文件 -t 目标镜像:[tag] 目标位置

[root@localhost dockerfile]# docker build -f dockerfile-mycentos -t mycentos:0.1 .
...
Step 9/9 : CMD /bin/bash
 ---> Running in d5083707b308
Removing intermediate container d5083707b308
 ---> b6a1205a01ec
Successfully built b6a1205a01ec
Successfully tagged mycentos:0.1
# 查看镜像
[root@localhost dockerfile]# docker images
REPOSITORY          TAG       IMAGE ID       CREATED          SIZE
mycentos            0.1       b6a1205a01ec   3 minutes ago    580MB
centos              7         eeb6ee3f44bd   6 months ago     204MB

3.运行测试
在这里插入图片描述

4.可以通过docker history命令来分析一个镜像的构建过程

# 通过 docker history 命令来分析刚刚构建的镜像过程
[root@localhost dockerfile]# docker history b6a1205a01ec
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
b6a1205a01ec   23 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
8c604ec85c0d   23 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
ad5af97ad072   23 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
3cdf414340ac   23 minutes ago   /bin/sh -c yum -y install vim                   216MB     
cdc69b9b3a21   24 minutes ago   /bin/sh -c yum -y install net-tools             161MB     
ff54b51b10da   24 minutes ago   /bin/sh -c #(nop) WORKDIR /usr/local            0B        
d62c8129ba70   24 minutes ago   /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B        
5bc36fed9ecf   24 minutes ago   /bin/sh -c #(nop)  MAINTAINER buckletime<187…   0B        
eeb6ee3f44bd   6 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      6 months ago     /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      6 months ago     /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB

实战2:CMD指令和ENTRYPOINT指令的区别

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

CMD指令测试

1.vim dockerfile-cmd

FROM centos:7
CMD ["pwd"]
CMD ["ls","-a"]

2.构建镜像

[root@localhost dockerfile]# docker build -f dockerfile-cmd -t cmd-test:1.0 .

3.运行测试

[root@localhost dockerfile]# docker run -it cbe86f605790
.   .dockerenv	       bin  etc   lib	 media	opt   root  sbin  sys  usr
..  anaconda-post.log  dev  home  lib64  mnt	proc  run   srv   tmp  var
# 要想追加命令 -l ,CMD指令会报错,只能使用全部命令去替换 ls -al
[root@localhost dockerfile]# docker run -it cbe86f605790 -l
docker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
[root@localhost dockerfile]# docker run -it cbe86f605790 ls -al
total 12
drwxr-xr-x.   1 root root     6 Apr  7 09:02 .
drwxr-xr-x.   1 root root     6 Apr  7 09:02 ..
-rwxr-xr-x.   1 root root     0 Apr  7 09:02 .dockerenv
-rw-r--r--.   1 root root 12114 Nov 13  2020 anaconda-post.log
lrwxrwxrwx.   1 root root     7 Nov 13  2020 bin -> usr/bin
drwxr-xr-x.   5 root root   360 Apr  7 09:02 dev
drwxr-xr-x.   1 root root    66 Apr  7 09:02 etc
drwxr-xr-x.   2 root root     6 Apr 11  2018 home
lrwxrwxrwx.   1 root root     7 Nov 13  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root     9 Nov 13  2020 lib64 -> usr/lib64
drwxr-xr-x.   2 root root     6 Apr 11  2018 media
drwxr-xr-x.   2 root root     6 Apr 11  2018 mnt
drwxr-xr-x.   2 root root     6 Apr 11  2018 opt
dr-xr-xr-x. 241 root root     0 Apr  7 09:02 proc
dr-xr-x---.   2 root root   114 Nov 13  2020 root
drwxr-xr-x.  11 root root   148 Nov 13  2020 run
lrwxrwxrwx.   1 root root     8 Nov 13  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root     6 Apr 11  2018 srv
dr-xr-xr-x.  13 root root     0 Apr  7 01:43 sys
drwxrwxrwt.   7 root root   132 Nov 13  2020 tmp
drwxr-xr-x.  13 root root   155 Nov 13  2020 usr
drwxr-xr-x.  18 root root   238 Nov 13  2020 var

ENTRYPOINT指令测试

1.vim dockerfile-entrypoint

FROM centos:7
ENTRYPOINT ["pwd"]
ENTRYPOINT ["ls","-a"]

2.构建镜像

[root@localhost dockerfile]# docker build -f dockerfile-entrypoint -t entrypoint-test:1.0 .

3.运行测试

[root@localhost dockerfile]# docker run -it 1ff2ec561a44
.   .dockerenv	       bin  etc   lib	 media	opt   root  sbin  sys  usr
..  anaconda-post.log  dev  home  lib64  mnt	proc  run   srv   tmp  var
# 追加命令 -l
[root@localhost dockerfile]# docker run -it 1ff2ec561a44 -l
total 12
drwxr-xr-x.   1 root root     6 Apr  7 09:06 .
drwxr-xr-x.   1 root root     6 Apr  7 09:06 ..
-rwxr-xr-x.   1 root root     0 Apr  7 09:06 .dockerenv
-rw-r--r--.   1 root root 12114 Nov 13  2020 anaconda-post.log
lrwxrwxrwx.   1 root root     7 Nov 13  2020 bin -> usr/bin
drwxr-xr-x.   5 root root   360 Apr  7 09:06 dev
drwxr-xr-x.   1 root root    66 Apr  7 09:06 etc
drwxr-xr-x.   2 root root     6 Apr 11  2018 home
lrwxrwxrwx.   1 root root     7 Nov 13  2020 lib -> usr/lib
lrwxrwxrwx.   1 root root     9 Nov 13  2020 lib64 -> usr/lib64
drwxr-xr-x.   2 root root     6 Apr 11  2018 media
drwxr-xr-x.   2 root root     6 Apr 11  2018 mnt
drwxr-xr-x.   2 root root     6 Apr 11  2018 opt
dr-xr-xr-x. 242 root root     0 Apr  7 09:06 proc
dr-xr-x---.   2 root root   114 Nov 13  2020 root
drwxr-xr-x.  11 root root   148 Nov 13  2020 run
lrwxrwxrwx.   1 root root     8 Nov 13  2020 sbin -> usr/sbin
drwxr-xr-x.   2 root root     6 Apr 11  2018 srv
dr-xr-xr-x.  13 root root     0 Apr  7 01:43 sys
drwxrwxrwt.   7 root root   132 Nov 13  2020 tmp
drwxr-xr-x.  13 root root   155 Nov 13  2020 usr
drwxr-xr-x.  18 root root   238 Nov 13  2020 var

实战3:Dockerfile 制作Tomcat镜像

1. 准备环境

准备Tomcat和jdk的压缩包

[root@localhost dockerfile]# ll
总用量 188324
-rwxr-xr-x. 1 root root  11560971 4月   7 17:26 apache-tomcat-9.0.62.tar.gz
-rwxr-xr-x. 1 root root 181260798 4月   7 17:26 jdk-8u65-linux-x64.tar.gz
-rw-r--r--. 1 root root         0 4月   7 18:39 readme.txt

2. 编写Dockerfile文件

官方名字是Dockerfile,直接使用此名字,构建时就不用再指定 -f

FROM centos:7
MAINTAINER buckletime<[email protected]>

ENV MYPATH /usr/local
WORKDIR $MYPATH

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

ADD jdk-8u65-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.62.tar.gz /usr/local/

RUN yum -y install vim

ENV JAVA_HOME /usr/local/jdk1.8.0_65
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.62
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.62
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

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

3. 构建镜像

[root@localhost dockerfile]# docker build -t mytomcat:2.0 .
Successfully built 874b2eaffc8f
Successfully tagged mytomcat:2.0

4. 启动镜像

[root@localhost dockerfile]# docker run -d -p 9090:8080 --name mytomcat \
-v /home/buckletime/dockerbuild/tomcat/project:/usr/local/apache-tomcat-9.0.62/webapps/project \
-v /home/buckletime/dockerbuild/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.62/logs mytomcat:2.0

访问测试:http://192.168.0.105:9090 成功进入Tomcat主页

5. 发布项目

由于做了卷挂载,直接将项目放在本地就可以发布项目了

实战4:SpringBoot项目打包成Docker镜像

  1. Springboot项目打包,这里以jar包为例

  2. 上传到Linux中,并编写Dockerfile文件

    [root@localhost idea]# ls
    demo-0.0.1-SNAPSHOT.jar  Dockerfile
    
    FROM java:8
    
    # 将demo-0.0.1-SNAPSHOT.jar 复制 到容器中并重命名为 app.jar
    COPY demo-0.0.1-SNAPSHOT.jar app.jar
    
    CMD ["--server.port=8080"]
    
    EXPOSE 8080
    
    ENTRYPOINT ["java","-jar","app.jar"]
    
  3. 构建镜像

    [root@localhost idea]# docker build -t springbootdemo:1.0 .
    [root@localhost idea]# docker images
    REPOSITORY       TAG                IMAGE ID       CREATED          SIZE
    springbootdemo   1.0                d9648a49a226   50 seconds ago   661MB	
    
  4. 运行、测试

    [root@localhost idea]# docker run -d -p:8888:8080 --name mydemo springbootdemo:1.0
    [root@localhost idea]# curl localhost:8888/hello
    hello buckletime![root@localhost idea]# 
    

实战5:发布镜像

发布镜像到Docker Hub

  1. Docker Hub官网,注册账号

  2. 使用docker login 登录账号

    [root@localhost ~]# docker login --help
    
    Usage:  docker login [OPTIONS] [SERVER]
    
    Log in to a Docker registry.
    If no server is specified, the default is defined by the daemon.
    
    Options:
      -p, --password string   Password
          --password-stdin    Take the password from stdin
      -u, --username string   Username
    
  3. 使用docker push 提交镜像

    # 发布镜像最好带上版本号,可以使用docker tag 命令修改镜像名称和版本号
    docker tag 6d27817ecb31 buckletime/mycentos:2.0
    # docker push 发布镜像
    docker push buckletime/mycentos:2.0
    

发布镜像到阿里云容器服务

  1. 登录阿里云,找到容器镜像服务
  2. 创建命名空间
  3. 创建容器镜像
  4. 根据容器镜像内的描述,发布镜像

四、Docker 总结

在这里插入图片描述

五、Docker 网络

先清空所有容器和镜像,方便学习

# 清空所有容器
docker rm $(docker ps -aq)
# 清空所有镜像
docker rmi $(docker images -aq)

5.1 了解Docker网络

在这里插入图片描述
1.运行一个Tomcat容器,tomcat01 ,并查看容器的地址

[root@localhost ~]# docker run -d -P --name tomcat01 tomcat
[root@localhost ~]# docker exec -it tomcat01 ip addr

在这里插入图片描述

运行时使用ip addr直接查看容器地址,有可能出现报错找不到ip命令,需要进入容器中安装iproute2
官方Tomcat中没有yum命令,使用apt-get命令安装iproute2和ping命令

[root@localhost ~]# docker exec -it tomcat01 /bin/bash
root@8e57c8b48890:/usr/local/tomcat# apt-get update
root@8e57c8b48890:/usr/local/tomcat# apt-get -y install iproute2 iproute2-doc
root@8e57c8b48890:/usr/local/tomcat# apt-get -y install inetutils-ping

由于容器的ip是docker分配的,容器与主机在同一个网段。Linux主机与容器之间能 ping 通

[root@localhost ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.081 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.046 ms

2.再运行一个Tomcat容器,tomcat02 ,并查看容器的地址

[root@localhost ~]# docker run -d -P --name tomcat02 tomcat
[root@localhost ~]# docker exec -it tomcat02 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
70: eth0@if71: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

可以发现:

  • 我们发现这个容器带来网卡,都是一对对的
  • evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的
  • OpenStac,Docker容器之间的连接,OVS的连接,都是使用 evth-pair 技术

3.两个tomcat01 和tomcat02之间能否ping通? 可以ping同,也在同一网段

[root@localhost ~]# docker exec -it tomcat02 ping 127.17.0.2
PING 127.17.0.2 (127.17.0.2): 56 data bytes
64 bytes from 127.17.0.2: icmp_seq=0 ttl=64 time=0.099 ms
64 bytes from 127.17.0.2: icmp_seq=1 ttl=64 time=0.051 ms

在这里插入图片描述
结论

  • 所有容器不指定网络的情况下,都是由docker0路由的,docker会给容器分配一个可用IP
  • Docker使用的是Linux的桥接
  • Docker中所有网络接口都是虚拟的,转发效率高

在这里插入图片描述

5.2 容器互联 --link

--link命令可以连接容器,使得容器之间可以使用容器名访问

[root@localhost ~]# docker exec -it tomcat02 ping tomcat01
ping: unknown host
# --link命令 连接容器 tomcat03 连接 tomcat02 
[root@localhost ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat
# tomcat03 能通过容器名访问 tomcat02
[root@localhost ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=0.137 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.061 ms
# 但是tomcat02 不能通过容器名访问 tomcat03
[root@localhost ~]# docker exec -it tomcat02 ping tomcat03
ping: unknown host

本质原理:--link是在hosts中增加了一个容器名称的映射关系,是单向连接的

[root@localhost ~]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	tomcat02 03da12909222
172.17.0.4	8e77f2a544a5

真实开发中,不推荐使用--link,配置是修改hosts文件,且是单向配置

5.3 容器互联 自定义网络

不使用docker0,因为docker0不支持使用容器名连接访问。使用自定义网络。

docker network命令

[root@localhost ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
9eeca5a5158c   bridge    bridge    local
c60f472b3848   host      host      local
a959f5564b21   none      null      local

网络模式

  • bridge:桥接(docker默认,自定义网络也是用桥接模式)
  • host:和宿主机共享网络
  • none:不设置网络
  • container:容器网络连接(局限性大,很少使用)

创建网络

docker network create 创建网络

  • --driver 模式(默认bridge)
  • --subnet 子网
  • --gateway 网关
# docker network create 创建网络
[root@localhost ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
2b9f9c88b69fbb9917c550d0b8017471e246aeb2c8b17c1667ece8a19b086bca
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
9eeca5a5158c   bridge    bridge    local
c60f472b3848   host      host      local
2b9f9c88b69f   mynet     bridge    local
a959f5564b21   none      null      local

我们自己的网络就创建好了:

docker network inspect mynet查看网络详情信息

在这里插入图片描述
启动容器指定网络 --net

[root@localhost ~]# docker run -d -P --name tomcat-net01 --net mynet tomcat
972542a6d6516b6d03d81493d03c1f60cecb5160e4ecdad44fb4d18e4430b03f
[root@localhost ~]# docker run -d -P --name tomcat-net02 --net mynet tomcat
f4fd35dcefcd8059af0b0a0c607b137b9c8d4c9d6ba0ae2cf6be23d8a3498992
# 这样两个容器可以直接使用容器名互相连接访问
[root@localhost ~]# docker exec -it tomcat-net01 ping tomcat-net02
PING tomcat-net02 (192.168.0.3): 56 data bytes
64 bytes from 192.168.0.3: icmp_seq=0 ttl=64 time=0.137 ms
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.061 ms

自定义网络好处

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

5.4 网络连通

docker network connect 网络 容器 将容器连接到网络中

[root@localhost ~]# docker network connect --help

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., 172.30.100.104)
      --ip6 string              IPv6 address (e.g., 2001:db8::33)
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container

测试

# 使用docker0启动两个tomcat
[root@localhost ~]# docker run -d -P --name tomcat04 tomcat
[root@localhost ~]# docker run -d -P --name tomcat05 tomcat
# tomcat04和 自定义网络mynet下的tomcat-net01连接,此时肯定是不通的
[root@localhost ~]# docker exec -it tomcat04 ping tomcat-net01
ping: unknown host
# docker network connect 将容器tomcat04连接到mynet网络中
docker network connect mynet tomcat04
# 再次连接,可以连通
[root@localhost ~]# docker exec -it tomcat04 ping tomcat-net01
PING tomcat-net01 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.137 ms
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.061 ms

docker network inspect mynet 查看网络详情信息,发现容器tomcat04被添加到mynet网络中,即:一个容器,有两个ip地址

在这里插入图片描述

5.5 Docker网络 实战

实战1:Redis集群部署

在这里插入图片描述

# 1.创建redis网络
[root@localhost ~]# docker network create redis_net --subnet 172.38.0.0/16 --gateway 172.38.0.1
# 2.通过shell脚本创建6个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.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
# 3.通过shell脚本启动6个redis容器
for port in $(seq 1 6); \
do \
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_net --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done
# 4.配置集群。进入一个redis容器中,注意,redis没有/bin/bash 命令,使用/bin/sh 
[root@localhost ~]# docker exec -it redis-1 /bin/sh
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1

配置集群命令执行后,出现下图信息说明,集群配置成功

在这里插入图片描述
5.redis集群测试

redis-cli -c 是进入redis集群, redis-cli是进入单机版redis

  • cluster info:查看集群信息
  • cluster nodes:查看集群节点信息
/data # redis-cli -c
127.0.0.1:6379> cluster nodes
8dea9b0ac434985556f08543f663a1d149772b75 172.38.0.11:6379@16379 myself,master - 0 1649398430000 1 connected 0-5460
29c361a494c043eb2597a3702537bf9553b89c95 172.38.0.16:6379@16379 slave c356c34a7fe0bf89b0abdcf538a910c1444da20e 0 1649398429000 6 connected
187da435dedcc35a48d0236bb8cbb2a2410d354e 172.38.0.15:6379@16379 slave 8dea9b0ac434985556f08543f663a1d149772b75 0 1649398430636 5 connected
17c460274af7f601846685dd91a39cc244823e17 172.38.0.14:6379@16379 slave 554f73de745a0dbdbe8bb8d805b93c622cb98a73 0 1649398429530 4 connected
554f73de745a0dbdbe8bb8d805b93c622cb98a73 172.38.0.13:6379@16379 master - 0 1649398429127 3 connected 10923-16383
c356c34a7fe0bf89b0abdcf538a910c1444da20e 172.38.0.12:6379@16379 master - 0 1649398430133 2 connected 5461-10922
127.0.0.1:6379> set name buckletime
-> Redirected to slot [5798] located at 172.38.0.12:6379
OK

在集群中set值,是随机处理(172.38.0.12)的。此时把172.38.0.12上的redis-2容器停止,模拟redis服务宕机,看看数据是否还在,是否还能得到刚才的值。

[root@localhost ~]# docker stop redis-2
redis-2
127.0.0.1:6379> get name
-> Redirected to slot [5798] located at 172.38.0.16:6379
"buckletime"

再次进入集群中,发现可以获得刚刚的值,说明数据没有受到影响,是高可用的。
再次查看集群节点信息,如下图:redis-2节点状态是fail,集群自动又选举出一个master
在这里插入图片描述

六、Docker Compose 单机部署

6.1 Docker Compose 介绍、安装

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

详细介绍可以参考Docker Compose官网,官网教程非常详细,可以多看官网。

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行 docker-compose up 命令来启动并运行整个应用程序。

docker-compose.yml 的配置案例如下:

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

理解两个概念

  • 服务 service,项目中使用的单个服务模块,比如web、redis、mysql…
  • 项目 project,一组关联的服务构成一个项目,比如博客…

Docker Compose 安装

Linux 中安装Docker Compose:1.下载 2.授权

# 下载 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 授权
sudo chmod +x /usr/local/bin/docker-compose

6.2 Docker Compose 快速体验

1.创建一个应用。python + flask + redis 实现的一个计数器。

vim 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)

vim requirements.txt,所需依赖包

flask
redis

2.创建Dockerfile

vim Dockerfile,构建Docker 镜像

# syntax=docker/dockerfile:1
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
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

3.定义docker-compose.yml

vim docker-compose.yml,在配置文件中定义服务信息

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

4.用Compose构建和运行应用程序

docker-compose up -d参数表示后台启动

[root@localhost demo_compose]# docker-compose up
Creating network "demo_compose_default" with the default driver
Building web
Sending build context to Docker daemon  4.608kB
Step 1/10 : FROM python:3.7-alpine
...
Creating demo_compose_web_1   ... done
Creating demo_compose_redis_1 ... done
...
web_1    |  * Running on http://127.0.0.1:5000
web_1    |  * Running on http://172.18.0.2:5000 (Press CTRL+C to quit)

由构建过程可以看出Compose的工作流程

  • 创建一个网络,名称为 “文件夹名称_default”
  • 读取docker-compose.yml配置文件
  • 根据配置文件中的服务定义,构建并启动服务

运行结果测试:

[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 1 times.
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 2 times.
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 3 times.
[root@localhost idea]# curl 172.18.0.2:5000
Hello World! I have been seen 4 times.

5.停止程序

  • Ctrl + C 非后台启动,可以使用此命令
  • docker-compose stop -d 后台启动可以使用此命令
  • docker-compose down [--volumes]

stop和down区别在于使用down会完全删除容器使用stop是停止一次。参数--volumes表示删除容器使用的数据卷

6.3 Docker Compose 默认命名规则

1.compose 服务名命名规则

使用docker ps查看正在运行的服务可以发现,服务名称的命名规则是文件夹名_服务名_num

[root@localhost idea]# docker ps
CONTAINER ID   IMAGE              NAMES					COMMAND                  CREATED          STATUS          PORTS                                       
f8d252c277d0   redis:alpine       demo_compose_redis_1  "docker-entrypoint.s…"	 18 minutes ago   Up 18 minutes   6379/tcp                                    
e29dfaeda7c5   demo_compose_web   demo_compose_web_1	"flask run"              18 minutes ago   Up 18 minutes   0.0.0.0:8000->5000/tcp, :::8000->5000/tcp

compose启动服务是以集群的方式启动的,num表示副本数量

2.网络名命名规则

使用docker network ls 查看网络列表,网络名的命名规则是文件夹名_default

[root@localhost idea]# docker network ls
NETWORK ID     NAME                   DRIVER    SCOPE
9eeca5a5158c   bridge                 bridge    local
5fcff058a02c   demo_compose_default   bridge    local
c60f472b3848   host                   host      local

这样,在同一个项目文件夹下,所有服务之间都可以通过域名进行访问

6.4 docker-compose.yml 配置规则

官网 docker-compose.yml 配置详细说明

version: "3.9"	# 1.版本
services:		# 2.服务
  web:	# 服务名
  	# 服务配置
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"
# 3.其他配置 网络/卷/全局规则等
volumes:
network:
config:

学习 docker-compose.yml 配置规则,最好的办法是多写多看!

6.5 实战:编写springboot项目通过Compose构建运行

1.编写微服务项目,自己实现一个计数器(redis)

引入redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

编写controller代码

@RestController
public class CounterController {
    
    

    @Autowired
    StringRedisTemplate redisTemplate;

    @RequestMapping("counter")
    public String counter(){
    
    
        Long views = redisTemplate.opsForValue().increment("views");
        return "hello, buckletime, views " + views + " times";
    }
}

application.properties配置文件

server.port=8080
# 配置redis 注意,不要写ip,直接写服务名再通过Compose构建服务
spring.redis.host=redis

最后将项目打成jar包

2.Dockerfile 构建镜像

FROM java:8

COPY *.jar app.jar

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

EXPOSE 8080

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

3.编写 docker-compose.yml 配置

version: "3.8"
services:
  mycounter:  # 服务名
    build: .  # . 表示使用当前目录下的 Dockerfile文件构建镜像
    image: mycounter  # 镜像
    depends_on:
      - redis   # depends_on 依赖 表示需要依赖redis服务
    ports:
      - "8080:8080"   # 端口映射
  redis:
    image: "redis:alpine"

4.通过Compose构建运行

[root@localhost mycounter]# ll
总用量 26884
-rwxr-xr-x. 1 root root 27520888 48 19:50 demo-0.0.1-SNAPSHOT.jar
-rwxr-xr-x. 1 root root      336 48 19:50 docker-compose.yml
-rwxr-xr-x. 1 root root      120 48 19:50 Dockerfile
[root@localhost mycounter]# docker-compose up -d

5.访问测试,运行成功

[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 1 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 2 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 3 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 4 times[root@localhost mycounter]# curl localhost:8080/counter
hello, buckletime, views 5 times[root@localhost mycounter]# 

七、Docker Swarm 集群部署

7.1 Swarm 相关概念

swarm

集群的管理和编排。docker可以初始化一个swarm集群,其他节点可以加入。

Node

就是一个docker节点。多个节点就组成了一个网络集群。(管理、工作者)

Service

服务,可以在管理节点或者工作节点来运行,核心!用户访问!

Task

容器内的命令,细节任务

swarm和k8s原理一样的

  • 命令 -> manager节点 -> api -> 调度 -> worker节点(创建维护Task)

7.2 Swarm 工作模式

Docker Swarm 工作模式 官方文档

1. Node工作模式
在这里插入图片描述
3. Service、Task、Container

将服务部署到 swarm 时,swarm 管理器会接受您的服务定义作为服务的所需状态。然后,它将 swarm 中节点上的服务计划为一个或多个副本任务。这些任务在群中的节点上彼此独立运行。

例如,假设您要在 HTTP 侦听器的三个实例之间实现负载平衡。下图显示了具有三个副本的 HTTP 侦听器服务。侦听器的三个实例中的每一个都是群中的一个任务。
在这里插入图片描述
3. Task、Scheduling

下图显示了 swarm 模式如何接受服务创建请求并将任务计划到工作节点。
在这里插入图片描述

7.3 Swarm 集群搭建

[root@localhost ~]# docker swarm --help

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 --advertise-addr 172.24.82.149 初始化一个节点

在这里插入图片描述

docker swarm join 加入一个节点

  • docker swarm join-token manager 获取manager令牌
  • docker swarm join-token worker 获取worker令牌

在这里插入图片描述

在另外两台机器上分别再加入节点,一个manager,一个worker。得到一个4节点的swarm集群

在这里插入图片描述
集群搭建总结

  • docker swarm init 初始化主节点
  • docker swarm join 加入节点(manager、worker)

7.4 了解Raft一致性协议

7.2示例中集群是两主两从,当Leader节点宕机时,另一个manager节点也无法工作,只有一个主节点存活无法重新选举出新的Leader;把其中一个worker节点更改为manager节点后,此时集群是三主一从,当Leader节点宕机时,另外两个manager节点都可以正常工作,因为此时可以选举出新的Leader。

leader选举:当前leader故障时必须选举出一个新的leader。

所以,要保证集群的高可用

  • 主节点数量必须>=3
  • 主节点存活数量必须>=2

简单来说,Raft协议:保证大多数节点存活才可以使用

7.5 Swarm集群动态扩缩容服务

[root@localhost ~]# docker service --help

Commands:
  create      Create a new service
  inspect     Display detailed information on one or more services
  logs        Fetch the logs of a service or task
  ls          List services
  ps          List the tasks of one or more services
  rm          Remove one or more services
  rollback    Revert changes to a service's configuration
  scale       Scale one or multiple replicated services
  update      Update a service

docker service create 创建并运行一个服务

[root@localhost ~]# docker service create -p 8888:80 --name myngnix ngnix
  • docker run 容器,不具备扩缩容
  • docker service 服务,具备扩缩容、滚动更新功能

docker service ls 查看服务列表

[root@localhost ~]# docker service ls
ID             NAME      MODE         REPLICAS   IMAGE          PORTS
blkxxbxk897b   myngnix   replicated   1/1        ngnix:latest   *:8888->80/tcp

动态扩缩容

  • docker service scale 服务名=num num 表示扩缩容的服务数量
  • docker service update --replicas num 服务名 num 表示扩缩容的服务数量
[root@localhost ~]# docker service scale myngnix=5
[root@localhost ~]# docker service update --replicas 3 myngnix

两个动态扩缩容命令等效。scale 方便一些

八、Docker 其他命令(了解)

8.1 Docker Stack

docker stack与 docker compose类似

  • docker compose 单机容器编排
  • docker stack 集群容器编排
[root@localhost ~]# docker stack --help

Usage:  docker stack [OPTIONS] COMMAND

Manage Docker stacks

Options:
      --orchestrator string   Orchestrator to use (swarm|kubernetes|all)

Commands:
  deploy      Deploy a new stack or update an existing stack
  ls          List stacks
  ps          List the tasks in the stack
  rm          Remove one or more stacks
  services    List the services in the stack

8.2 Docker Secret

安全、密码配置、证书等

[root@localhost ~]# docker secret --help

Usage:  docker secret COMMAND

Manage Docker secrets

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

8.3 Docker Config

统一配置

[root@localhost ~]# docker config --help

Usage:  docker config COMMAND

Manage Docker configs

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

猜你喜欢

转载自blog.csdn.net/weixin_45698637/article/details/123999825