Docker 知识点总结

我的博客地址:www.lss-coding.top

1. Docker 简介

image-20211025200059178

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 LinuxWindows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

Dcoker 是基于 Go 语言开发的,是一个开源项目。

官网:https://www.docker.com/

仓库:https://hub.docker.com/,相当于 GitHub ,可以发布镜像

1.1 Docker 为什么会出现?

当开发一款产品的时候,需要有开发和上线两套环境,不同环境需要使用不同的配置。

公司中会有两个角色:开发和运维。

问题:当我开发人员开发好一款产品之后再自己的电脑上可以运行,如果版本更新的话会导致服务器不可用的,对于运维人员来说是非常麻烦的。

环境配置非常的麻烦,每一个机器都要部署环境(集群 Redis 、ES、Hadoop)等等非常的费时费力。

发布一个项目的时候是以 jar 的方式,但是需要依赖一些环境(Rdis、MySQL、JDK 等),项目不能都带上环境安装打包。

假设之前在服务器配置一个应用的环境 Redis、MySQL、JDK,配置非常的麻烦,不能够实现跨平台,开发系统 Windows ,发布到 Linux

传统的开发中:开发人员打 jar 包,运维人员来进行部署上线

现在:开发打包部署上线,一套流程做完。

假设开发一个 apk 应用

  • java – apk – 发布(应用商店)-- 用户使用 apk – 安装使用就可以
  • java – jar(环境)-- 打包项目带上环境(镜像)-- (Docker仓库)-- 下载发布的镜像 – 直接运行就可以。

Docker 对于上面的问题提出解决方案。

Docker 的思想就来自于集装箱。

JRE – 多个应用(端口冲突)-- 原来都是交叉的。

隔离:Docker 核心思想,打包装箱,每个箱子都是互相隔离的,Docker 通过隔离机制,可以将服务器利用到机制。

1.2 Docker 的历史

2010 年,几个做 IT 的年轻人,在美国成立了一家公司“dotCloud”

这个公司开始是做一些 pass 的云计算服务的,LXC 有关的容器技术,它们将自己的技术(容器化技术)命名就是 Docker,Docker 刚刚诞生的时候,没有引起行业的注意,公司坚持不下去。

所以就选择了开源,2013 年 Docker 开源,开源之后越来越多的人发现了 Docker 的优点,火了之后 Docker 每一个月都会更新一个版本。2014 年 4 月 9 日,Docker1.0 发布。

在容器技术出现之前,我们都是使用的虚拟机技术。

虚拟机:在 windows 中装一个 vmware,通过这个软件我们可以虚拟出来一台或者多台电脑,非常的笨重。

虚拟机也是属于虚拟化技术;Docker 容器技术,也是一种虚拟化技术。

1.3 Docker 能干什么

虚拟机技术

一个电脑,电脑中有一个内核,一个运行需要的库,然后所有开发的软件运行在这个电脑上。

虚拟机技术缺点:

  1. 资源占用非常多
  2. 冗余步骤多(每次使用都需要手动开启)
  3. 开启的客户端多了启动很慢

image-20211025201945509

容器化技术

容器化技术不是模拟的一个完整的操作系统。

image-20211025202243145

  • 比较不同

虚拟机是虚拟出一套硬件,运行一个完整的操作系统,在这个系统上安装和运行软件。

容器内的应用直接运行在宿主机的内容,容器是没有自己的内核的,也没有虚拟硬件,所以非常的轻便,每个容器之间是相互隔离,每个容器内都有一个属于自己的文件系统,互不影响。

2. Docker 安装

2.1 Docker 的基本组成

image-20211025203132491

  • 镜像(image):

镜像就好比一个模板,可以通过这个模板来创建容器服务,假设有一个 tomcat 镜像,通过 run 方法运行,tomcat01 容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。

  • 容器(container):

利用容器技术做到独立运行一个或者一组应用,通过镜像来创建,可以假设容器就是一个简易的 Linux 系统

  • 仓库(repository)

用来存放镜像的地方,仓库分为公有仓库和私有仓库

Docker Hub 默认的国外的,阿里云、腾讯云等都有容器服务器

2.2 安装 Dcoker
  • 环境准备

一台 Linux 系统的服务器,CentOS 7

安装

参考地址:https://docs.docker.com/engine/install/centos/

  1. 卸载旧的版本
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  1. 安装需要的安装包
sudo yum install -y yum-utils
  1. 设置镜像的仓库
# 国外的,非常慢
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
    
# 阿里云镜像安装地址
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 更新 yum 软件包索引
yum makecache fast
  1. 安装 docker 相关
sudo yum install docker-ce docker-ce-cli containerd.io

yum install docker-ce-18.06.1.ce-3.el7 docker-ce-selinux-18.06.1.ce-3.el7

sudo yum install docker-ce-18.06.1.ce-3.el7 docker-ce-cli-18.06.1.ce-3.el7 containerd.io
  1. 启动 docker
systemctl start docker
  1. 使用 docker version 查看是否安装成功

image-20211026152318968

  1. 测试 Hello,World
docker run hello-world

image-20211026152519821

  1. 查看一下下载的 hello-world 镜像
docker images

image-20211026152631368

  1. 卸载 docker
# 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 删除运行环境
rm -rf /var/lib/docker
/var/lib/docker //docker 的默认工作路径
2.3 Dcoker Run 的运行流程

image-20211026153419229

Docker 是怎么工作的?

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

image-20211026153906393

Dcoker 为什么比 VM 快?

  1. Docker 有着比虚拟机更少的抽象层
  2. Dcoker 利用的是宿主机的内核,vm 需要的是 GuestOS

新建一个容器的时候,docker 不需要像虚拟机一样重新加载一个操作系统内核,避免引导。虚拟机是加载 GuestOS,是分钟级别的;docker 是利用宿主机的操作系统,省略了复杂的引导过程,是秒级的。

image-20211026154007239

3. Docker 常用命令

3.1 帮助命令
docker version	#显示 docker 的版本信息
docker info		#显示 docker 的系统信息,包括镜像和容器数量
docker 命令 --help #帮助信息

帮助文档地址:https://docs.docker.com/reference/

3.2 镜像命令
  • docker images

    查看所有本地的主机上的镜像

REPOSITORY          TAG                 IMAGE ID            CREATED      SIZE
hello-world         latest              feb5d9fea6a5        4 weeks ago  13.3kB
# 解释
REPOSITORY	镜像的仓库源
TAG			镜像的标签
IMAGE ID	镜像的 id
CREATED		镜像的创建时间
SIZE		镜像的大小

# 命令可选项
  -a, --all           	列出所有镜像
      --digests         Show digests
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print images using a Go template
      --no-trunc        Don't truncate output
  -q, --quiet           只显示镜像 id
  • docker search

    搜索镜像

docker search mysql

NAME                   DESCRIPTION                                     STARS       OFFICIAL     AUTOMATED
mysql                  MySQL is a widely used, open-source relation…   11587               [OK]
mariadb                MariaDB Server is a high performing open sou…   4407                [OK]
mysql/mysql-server     Optimized MySQL Server Docker images. Create…   857                 [OK]

# 可选项 ,过滤
	--filter=STARS=3000		搜索出来的镜像就是 STARS 大于 3000 的
	
  • docker pull

    下载镜像

docker pull mysql [:tags]  # 下载最新的  [:tags]指定下载

Using default tag: latest # 如果不写 tag,默认就是 latest 最新版
latest: Pulling from library/mysql
b380bbd43752: Pull complete	# 分层下载,docker image 的核心,联合文件系统,这回下了这几个层,如果下面指定别的版本进行下载,如果有重复就不会下载
f23cbf2ecc5d: Pull complete
30cfc6c29c0a: Pull complete
b38609286cbe: Pull complete
8211d9e66cd6: Pull complete
2313f9eeca4a: Pull complete
7eb487d00da0: Pull complete
4d7421c8152e: Pull complete
77f3d8811a28: Pull complete
cce755338cba: Pull complete
69b753046b9f: Pull complete
b2e64b0ab53c: Pull complete
Digest: sha256:6d7d4524463fe6e2b893ffc2b89543c81dec7ef82fb2020a1b27606666464d87  # 签名
Status: Downloaded newer image for mysql:latest
  • docker rmi

    删除镜像,可以通过镜像 id 删除或者镜像名

docker rmi -f IMAGE ID # 删除指定的容器,也可以通过空格间隔删除多个
docker rmi -f $(docker images -aq) # 删除全部的容器
3.3 容器命令

注意:我们有了镜像才可以创建容器

测试使用,下载一个 CentOS 镜像

docker pull docker  # 最新版的

新建容器并启动

docker run [可选参数] image

# 参数说明
--name="Name"   容器启动后的名字,用来区分容器
-d				后台方式运行
-it				使用交互方式运行,进入容器查看内容
-p				指定容器的端口  -p 8080
	-p	# ip:主机端口:容器端口
	-p	# 主机端口:映射到容器端口(常用)
	-p	# 容器端口
-P				随机指定端口

# 使用容器
# 启动并进入容器
docker run -it centos /bin/bash

# 从容器中退回到主机
exit	容器停止并退出
Ctrl + P + Q   容器不停止退出

# 列出所有运行中的容器
docker ps  列出正在运行的容器
docker ps -a  列出当前正在运行的容器 + 历史运行过的容器

-n=?	显示最近创建的容器
-q		只显示容器的编号

删除容器

docker rm 容器id		# 删除指定id 的容器
docker rm -f $(docker ps -aq)		# 删除所有的容器

启动和停止容器

docker start 容器id
docker restart 容	器id
docker stop 容器id
docker kill 容器id
3.4 其他常用命令

问题:当我们使用后台启动容器 centos 的时候docker run -d 镜像名,使用 docker ps 发现 centos 停止了。这里是常见的一个问题,容器使用后台运行,就必须要有一个前台进程,docker 发现没有应用就会自动停止;假设 nginx 容器启动后,发现自己没有提供服务,就会立刻停止,就没有程序了。

  • docker logs

    查看日志命令

docker logs -f -t --tail 5 容器    查看某一个容器的日志信息

image-20211026185054355

  • docker top

    查看容器中的进程信息

docker top 容器id
  • docker inspect

    查看镜像的元数据

docker inspect

image-20211026185613510

  • docker exec -it 容器id bashShell

    进入容器后开启一个新的终端,可以在里面操作(常用)

    进入当前正在运行的容器

    我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置

image-20211026190234310

docker attach 容器id 进入容器正在执行的终端,不会启动新的进程。

  • docker cp

    从容器中拷贝文件到主机上

docker cp 容器id:容器内路径 目的主机路径

image-20211026204838026

image-20211026205028772

3.5 总结
attach		# 当前 shell 下 attache 连接指定运行镜像
build		# 通过 Dockerfile 定制镜像
commit		# 提交当前容器为新的镜像
cp			# 从容器中拷贝指定文件或者目录到宿主机上
create		# 创建一个新的容器,同run,但不启动容器
diff		#查看docker 容器变化
events		# 从 docker 服务获取容器实时时间
exec		# 在已存在的容器上运行命令
export		# 导出容器的内容流作为一个 tar 归档文件[对应 import]
history		# 展示一个镜像形成历史
images		# 列出系统当前镜像
import		# 从tar 包中的内容创建一个新的文件系统镜像[对应export]
info		# 显示系统相关信息
inspect		# 查看容器详细信息
kill		# kill 指定 docker 容器
load		# 从一个 tar 包中加载一个镜像[对应save]
login		# 注册或者登录一个docker 源服务器
logout		# 从当前Docker registry 退出
logs		# 输出当前容器日志信息
port		# 查看映射端口对应的容器内部源端口
pause		# 暂定容器
ps			# 列出容器列表
pull		# 从docker 镜像源服务器拉取指定镜像或者库镜像
push		# 推送指定镜像或者库镜像至docker 源服务器
restart		# 重启运行的容器
rm			# 移除一个或者多个容器
rmi			# 移除一个或者多个镜像[无容器使用该镜像才可删除,否则需要删除相关容器才可以继续 或 -f 强制删除]
run			# 创建一个新的容器并运行一个命令
save		# 保存一个镜像为一个tar包[对应 load]
search		# 在 docker hub 中搜索镜像
start		# 启动容器
stop		# 停止容器
tag			# 给源中镜像打标签
top			# 查看容器中运行的进程信息
unpause		# 取消暂停容器
version		# 查看docker 版本号
wait		# 截取容器停止时间的退出状态值

4. Docker 安装使用

4.1 Docker 安装 Nginx
  1. 搜索镜像
docker search

也可以在 docker.hub 上搜索,可以看到帮助文档

image-20211026212041337

  1. 下载镜像
docker pull nginx

image-20211026212144793

  1. 运行测试
docker run -d --name nginx01 -p 3344:80 nginx

-d		# 后台运行
-name	# 容器名
-p		# 宿主机端口:容器内部端口

image-20211026212415955

  • 端口暴露的概念

image-20211026212743811

image-20211026212829392

4.2 Docker 安装 Tomcat
  1. 搜索镜像
docker search tomcat
  1. 下载镜像
docker pull tomcat
  1. 运行测试
docker run -d --name tomcat01 -p 8080:8080 tomcat
  1. 外网访问测试

    通过外网我们访问可以看到,结果是 404,因为 docker 下载下来的这个 tomcat 不是一个完整版的

image-20211026215008147

​ 我们使用命令进入容器查看

docker exec -it tomcat01 /bin/bash

whereis tomcat

​ 进入到 tomcat 的目录下,我们看到 webapps 目录下是空的,因为部署的项目是在这个目录下的,而看到这个文件夹是空的,所以表示并没有进行任何的项目部署,所以会出现 404 页面的情况,这个原因是阿里云镜像的原因,在下载的时候默认是找的最小的镜像,所以它会把不必要的都剔除掉,保证最小可运行的环境。我们在 webapps 的同级目录下可以 看到一个 webapps.dist 目录,将这个目录的内容全部复制到 webapps 里面,然后重新访问就可以看到 tomcat 的首页内容了。

image-20211026215433259

5. 可视化面板 portainer

Docker 图形化界面管理工具,提供一个后台面板供我们操作。

开启命令

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

image-20211027081718333

下载完成之后我们可以通过浏览器访问 ip地址:8088 端口号

image-20211027081804661

image-20211027081826184

image-20211027081948807

6. 镜像

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

所有的应用直接打包成 docker 镜像就可以直接运行。

获得镜像的方式:1. 从远程下载 2. 别人拷贝 3. 自己制作一个镜像DockerFile

6.1 UnionFS(联合文件系统)

在我们下载镜像的时候可以看到一层层的下载

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

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

6.2 Docker 镜像加载原理

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

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

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

image-20211027083409411

平时我们安装的虚拟机 CentOS 都是好几个 G,为什么 Docker 只有几百M?

image-20211027083652247

对于一个精简的 OS,rootfs 可能很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用 Host 的 kernel,自己只需要提供 rootfs 就可以了。由此可见对于不同的 Linux 发行版,bootfs 基本是一致的,rootfs 会有差别,因此不同的发行版可以公用 bootfs。虚拟机是分钟级别的,容器是秒级。

6.3 镜像分层

在我们下载一个镜像的时候,终端输出的日志中可以明显的看到是一层一层的进行下载。

image-20211027084023357

image-20211027084234487

为什么 Docker 镜像要采用这种分层的结构呢?

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

查看镜像分层的方式可以通过命令:docker image inspect 镜像


所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

假设基于 Unbuntu Linux 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python 包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

下图中镜像包含 3 个镜像层

image-20211027084836326

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,下图中,每个镜像包含 3 个文件,而镜像包含了来自两个镜像层的 6 个文件

image-20211027085012732

下图中是一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,因为最上层的文件 7 是文件 5 的更新版本。

image-20211027085253935

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件,这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。

Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。每种存储引擎都是基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和 CoW。

下图中是系统显示相同的三层镜像,所有镜像层堆叠并合并,对外提供统一的视图。

image-20211027085725209

特点

Docker 镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部,这一层就是我们通常说的容器层,容器层之下的都叫镜像层。

image-20211027090654048

6.4 Commit 镜像
docker commit 提交容器成为一个新的副本

docker commit -m="信息描述" -a="作者" 容器id 目标镜像名:[TAG]

在我们平常是使用中,下载一个镜像使用时需要对其进行一些修改,扩充,如果我们想要保存当前容器的状态,可以通过 commit 来提交,获得一个镜像,就好比 VM 虚拟机的快照功能。

  1. 在上面启动 tomcat 后 webapps 里面是没有东西的,所以访问 404
  2. 自己拷贝内容进 webapps
  3. 下面的命令进行提交为一个镜像,以后使用就可以通过我们修改过的镜像
docker commit -m="add webapps" -a="lss" xxxxxx tomcat001:1.0

image-20211027093002791

7. 容器数据卷

7.1 什么是容器数据卷

总的来说:容器的持久化和同步操作;容器间也是可以容器共享的

docker 的理念就是将应用和环境打包成一个镜像,如果数据存储在容器中,那当我们的容器被删除了,数据也会丢失。我们需要对数据进行持久化,加入 MySQL 的容器中存储了数据,容器突然被误删除了,那数据就会丢失了,所以我们需要将数据存储在本地。

容器之间可以有多个数据共享的技术,Docker 容器中产生的数据同步到本地,这就是卷技术,目录的挂载,将我们容器内的目录挂载到 Linux 上。

image-20211027093702509

7.2 通过命令挂载
docker run -it -v 主机目录:容器内目录

# 测试
docker run -it -v /home/test:/home centos /bin/bash

执行命令之后,无论是在镜像里面修改指定的目录还是在宿主机上修改指定的目录,另一方都能收到相应的变化信息,这种情况就是挂载成功了。

启动之后我们可以通过 docker inspect 容器id 来查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J9vy6dPh-1635640517571)(D:\notes\Docker\Docker 知识点总结.assets\image-20211027095035103.png)]

这里当我们停止运行容器之后,修改宿主机共享的文件的内容的,再次启动容器会发现数据也进行了相应的更新。双向的过程。

使用容器卷好处:绑定之后,我们修改本地的文件,在容器中也会进行同步修改。

7.3 安装 MySQL
  1. 搜索镜像
docker search mysql
  1. 拉取镜像
docker pull mysql:5.7
  1. 启动容器

    这里应该注意,进入 mysql 需要有一个密码的配置

    详细信息官网地址:https://registry.hub.docker.com/_/mysql

-d		# 后台运行
-p		# 端口映射   宿主机端口:容器端口
-v		# 卷挂载
-e		# 环境变量
--name	# 容器名字

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=root --name mysql01 mysql:5.7
  1. 查看宿主机挂载的目录

image-20211027102724230

  1. 使用 SQL_yog 连接MySQL

    创建一个 test 数据库

image-20211027102808296

  1. 查看 /home/mysql/data 目录下的内容

image-20211027102855455

  1. 假设将容器删除,我们发现挂载在本地的数据卷依旧没有丢失,这就实现了容器的持久化功能
7.4 具名挂载和匿名挂载
7.4.1 匿名挂载
-v 容器内路径
docker run -d -p 80:80 -v /etc/nginx nginx
查看所有的 volume 情况
docker volume ls
这里发现,这种就是匿名挂载,我们在 -v 只写了容器内的路径 ,没有写容器外的路径

image-20211027104316262

7.4.2 具名挂载
-v 卷名:容器内路径

docker run -d -p 80:80 -v nginx01:/var/nginx nginx

image-20211027104559723

image-20211027104657132

7.4.3 卷挂载路径查看

所有的 docker 容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data ,我们通过具名挂载可以方便的找到我们的一个卷,大多数情况使用 具名挂载

image-20211027104859517

7.4.4 确定挂载方式

如何确定是具名挂载、匿名挂载、还是指定路径挂载?

-v 容器内路径			# 匿名挂载
-v 卷名:容器内路径		   # 具名挂载
-v /宿主机路径:容器内路径		# 指定路径挂载
  • 读写权限
docker run -d -p 80:80 -v nginx01:/var/nginx:ro nginx
docker run -d -p 80:80 -v nginx01:/var/nginx:rw nginx

#通过 -v 容器内路径:ro  rw  改变读写操作
ro		readonly #只读		说明这个路径只能通过宿主机来操作,容器内部是无法操作的
rw		readwrite	#可读可写
#设置了这两个容器的权限,容器对我们挂载出来的内容就有限定了。
7.5 简单使用 DockerFile

DockerFile 就是用来构建 docker 镜像的构建文件,就是一个命令脚本

在 /home/docker-test-volume 目录下创建一个 dockerfile01 脚本文件,这个脚本可以生成镜像,里面的每一个命令都是一层

# 文件中的内容  这里面的每一个命令就是镜像的一层
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "---end---"
CMD /bin/bash

使用命令构建镜像

在 dockerfile01文件同级目录下

docker build -f dockerfile1 -t lss/centos .

image-20211027112038418

使用命令 docker images 查看我们刚才构建的镜像

image-20211027112214024

启动一下自己写的容器

docker run -it a542aa955836 /bin/bash

image-20211027112602461

在容器中的 volume01 下创建一个 container.txt 文件

image-20211027113344574

这个卷和外部一定有一个同步的目录,这里的是匿名挂载

使用命令 docker inspect 5c26b2ee40af 查看详细的信息

image-20211027113038037

image-20211027113238775

7.6 数据卷容器

多个容器实现数据的同步

image-20211027132020786

测试

  1. 启动 centos 镜像
docker run -it --name centos01 lss/centos

image-20211027132445753

  1. 在启动一个 lss/centos 镜像

    通过 --volumes-from 挂载到上一个启动的容器上实现数据的同步

--volumes-from  # 相当于一个继承的关系
docker run -it --name centos02 --volumes-from centos01 lss/centos

image-20211027132820837

  1. 在 centos01 的 volume01 文件夹下创建一个 test.java 文件

    进入 centos02 后在 volume02 文件夹下也可以看到这个文件,实现了容器之间的数据同步。

    因为这个镜像是自己创建的,在上面的 DockerFile 里面进行了设置,只设置了 volume01 和 volume02 文件夹是共享的卷,所以在别的文件夹中的内容是不能实现共享的。

加入一个 centos03 也挂载到 centos01上,然后删除掉 centos01 之后,这些共享的文件在 centos02 和 centos03 上并不会丢失的,这个文件都是双向拷贝存在的。

结论

容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止,但是一旦将数据同步到本地,本地的数据是不会删除的。

8. DockerFile

Dockerfile 就是用来构建 docker 镜像的文件,通过它来生成一个镜像文件发布出去,可以理解为一个命令参数脚本。

8.1 DockerFile 介绍

查看官网:https://registry.hub.docker.com/

image-20211027200047216

image-20211027200112021

这个文件里面就是一些构建的命令

很多官网镜像都是基础包,很多功能是没有的,我们通常会自己搭建自己的镜像。

8.2 DockerFile 构建和指令

构建时需要很多的指令

8.2.1 基础
  • 每个关键字(指令)都是必须是大写字母

  • 执行从上到下顺序执行

  • ( # ) 表示注释

  • 每一个指令都会创建提交一个新的镜像层,并提交

  1. 编写一个 dockerfile 文件

  2. docker build 构建成为一个镜像

  3. docker run 运行镜像

  4. docker push 发布镜像(DockerHub、阿里云镜像仓库)

image-20211027201300190

DockerFile 是面向开发的,以后要想发布项目,做镜像,就要编写 DockerFile 文件。

步骤:开发、部署、运维

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

DockerImages:通过 DockerFile 构建生成的镜像,最终发布和运行

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

8.2.2 DockerFile 指令

image-20211027201802145

FROM		# 基础镜像,一切从这里开始
MAINTAINER	# 镜像是谁写的  姓名 + 邮箱
RUN			# 镜像构建的时候需要运行的命令
ADD			# 步骤:tomcat 镜像,这个tomcat 压缩包,添加内容
WORKDIR		# 镜像的工作目录
VOLUME		# 挂载的目录
EXPOSE		# 保留端口配置
CMD			# 指定这个容器启动的时候需要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT	# 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD		# 当构建一个被继承 DockerFile 这个时候就会运行 ONBUILD 的指令,触发指令
COPY		# 类似 ADD ,将我们文件拷贝到镜像中
ENV			# 构建的时候设置环境变量
8.3 DockerFile 构建镜像

Docker Hub 中 99% 镜像都是从这个基础镜像过来的: FROM scratch,然后配置需要的软件和配置来进行构建。

image-20211027203202923

  1. 编写 Dockerfile 的文件
FROM centos
MAINTAINER lss<18764197362qq.com>

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

image-20211027204526391

  1. 通过这个文件构建镜像
docker build -f 文件名 -t 镜像名:[tag] .

docker build -f mydockerfile-centos -t centos:1.0 .   # 注意后面这个 . 不能少

image-20211027204554715

  1. 测试运行
docker run -it mycentos:1.0  # 进入我们自己创构建的镜像

这里我们在 DockerFile 文件中有安装 net-tools 和 vim 的命令,所以在镜像中可以只用;官网的下载的原生的是不能使用的。

8.4 CMD 和 ENTRYPOINT 区别
  • CMD:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
  • ENTRYPOINT:指定这个容器启动的时候要运行的命令,可以追加命令

测试 CMD

  1. 创建一个文件 dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
  1. 构建镜像docker build -f dockerfile-cmd-test -t cmdtest .

image-20211027212205442

  1. 运行镜像 docker run 037860b45b64,在 run 的时候 ls -a 命令生效

image-20211027212243780

  1. 想要在这个镜像上追加一个命令 docker run 037860b45b64 -l 会出错

image-20211027212537804

	因为 cmd 的情况下,-l 替换了 CMD ["ls","-a"] 命令,-l 不是命令所以报错

​ 这里可以使用 docker run 037860b45b64 ls -l 查看

image-20211027212743682

测试 ENTRYPOINT

  1. 创建一个 dockerfile-entrypoint-test 文件
FROM centos
# 与 CMD 区别之处
ENTRYPOINT ["ls","-a"]
  1. 构建镜像 docker build -f dockerfile-entrypoint-test -t entrytest .
  2. 运行测试 docker run 368a821b1dcb

image-20211027213516817

  1. 在执行的时候追加一个参数 docker run 368a821b1dcb -l

    这里还是可以正常执行的,这里是直接拼接在 ENTRYPOINT 后面的

image-20211027213617827

8.5 构建一个 tomcat 镜像
  1. 准备镜像文件 tomcat 压缩包,jdk 压缩包

image-20211028083527006

  1. 编写 dockerfile 文件,使用官网命名 Dockerfile,这样 build 的时候就会自动寻找这个文件,不需要使用 -f 指定了
FROM centos
MAINTAINER lss<1876419736@qq.com>

COPY README.txt /readme.txt
ADD jdk-8u311-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.54.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/bin/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.54
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.54
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.54/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.54/bin/logs/catalina.out
  1. 构建
docker build -t dirtomcat .		# 由于文件名是 Dockerfile ,所以不需要用 -f 参数去找文件
  1. 查看构建的镜像文件
docker images

image-20211028085851773

  1. 启动镜像测试
docker run -d -p 8080:8080 --name lss-tomcat -v /opt/build/tomcat/webapps:/usr/local/apache-tomcat-9.0.54/webapps/test -v /opt/build/tomcat/tomcat-logs/:/usr/local/apache-tomcat-9.0.54/logs diytomcat

image-20211028092511944

image-20211028092524800

  1. 本地编写一个项目进行发布

    上面启动镜像的时候就已经做了卷的挂载,所以我们直接在本地编写项目就可以实现同步发布了

    /opt/build/tomcat/webapps/ 文件夹(上面 -v 挂载的)下创建一个 WEB-INF 文件夹,在这个文件夹下创建一个 web.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0"
         metadata-complete="true">
</web-app>

在 tomcat 目录下创建一个 index.jsp 文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello Tomcat Docker!</h2>
<%
        System.out.println("--- tomcat test ---");
%>
</body>
</html>

至此已经实现了项目的发布

  1. 测试

image-20211028093750127

image-20211028093806277

查看日志文件输出信息

image-20211028093859845

9. 发布镜像

9.1 发布到 DockerHub
  1. 到 docker.hub 中注册一个账号登录进去

  2. 在服务器上提交镜像

    登录

docker login -u lishisen -p ******

image-20211028094939565

image-20211028095034234

  1. 登录完毕之后就可以提交镜像了
# 由于之间创建的镜像没有带版本号,所以提交的时候被拒绝了
# 增加一个 tag
docker tag 容器id lishisen/tomcat:1.0
# 然后提交就成功了
docker push lishisen/tomcat:1.0

image-20211028095709723

可以看到,提交的时候也是按照镜像的层级来进行提交的。

image-20211028100617193

9.2 发布到阿里云
  1. 登录阿里云
  2. 找到容器镜像服务

image-20211028100810644

  1. 创建一个命名空间

    这个命名空间可能就是一个很大的项目

image-20211028100946119

  1. 创建镜像仓库

image-20211028101041773

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jg6a2qWo-1635640517631)(D:\notes\Docker\Docker 知识点总结.assets\image-20211028101215250.png)]

  • 操作指南里面有详细的操作步骤

根据操作指南操作

  1. 登录
docker login --username=李时森111 registry.cn-beijing.aliyuncs.com

image-20211028101354545

  1. 为镜像生成一个版本号
docker tag [ImageId] registry.cn-beijing.aliyuncs.com/lishisen/lishisen-repo:[镜像版本号]

image-20211028103513949

  1. push 上传
docker push registry.cn-beijing.aliyuncs.com/lishisen/lishisen-repo:[镜像版本号]

image-20211028103429647

image-20211028103641925

image-20211028103717273

10. Docker 网络

10.1 Docker0

image-20211028110131348

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

有一个 tomcat 容器,一个 mysql 容器,那这两个容器之间是怎样通信的,是使用那个网络进行通信的?

image-20211028110257947

查看能够 ping 同容器内的 ip 地址

  1. 运行一个容器
docker run -d -P --name tomcat01 tomcat
  1. 查看容器内部 ip 地址

    在运行容器的时候加上 ip addr 命令

docker exec -it tomcat01 ip addr
# 注意这里下载的镜像如果这个命令不能用可能是镜像中没有这一个功能,可以上面安装过 net-tools 的 Dcokerfile 文件来自己重新构建一个镜像文件

启动后我们可以看到容器内部网络地址 ,容器启动的时候会得到一个 eth0@if33 的ip 地址,这是 docker 分配的。

image-20211028132905629

我们使用 ping 命令是可以 ping 通这个 ip 地址的

image-20211028133050265

原理

当我们每启动一个 docker 容器的时候,docker 就会给 docker 容器分配一个 ip 地址;在宿主机上,只要我们安装了 docker ,就会有一个 docker0 的网卡,是使用的桥接模式,使用 veth-pair 技术。

当我们上面的容器启动之后,在宿主机上使用 ip addr 查看,可以看到有刚才启动的容器的 ip 的相关信息。

我们每启动一个容器就会多一个网卡,这个启动的容器带来的网卡都是一对一对出现,这就是 veth-pair 技术:就是一对虚拟设备接口,它们都是成对出现的,彼此相连的。

也就是因为有了这个特性,veth-pair 充当作为一个桥梁,连接这各种的虚拟网络设备,实现宿主机和容器之间的互联。

image-20211028134352498

image-20211028133457879

加入我们开启了两个容器 tomcat01、tomcat02 ,这两个容器之间也是可以通过ping 命令测试连通的,所以说容器之间也是可以相互通信的。

image-20211028135232805

两个容器之间的通信并不是直接通信的,当安装 Docker 后会有一个 docker0 的网卡,这个就相当于是一个路由器,当 tomcat01 与 tomcat02 建立连接时,以 veth-pair 技术实现两个网卡之间的互联,然后路由器通过广播的方式或注册IP地址的方式进行发送连接。

tomcat01 和 tomcat02 是共用一个路由器 docker0。

所有的容器不指定网络的情况下,都是 docker0 路由的,docker 会给我们的容器分配一个默认的可用的 ip

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

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

只要删除容器,对应的一对网桥就没了

image-20211028135900904

10.2 link

场景:有一个微服务,database url = ip:,每一次用 docker 启动 MySQL 都会分配一个新的 ip ,如果 ip 变化了项目中的地址就会失效了,我们在项目不重启的情况下,数据库的 ip 地址换掉了,希望可以通过名字来访问这个容器,以此来解决这个问题。Docker 中使用 --link 来解决这个问题

  1. 启动两个 tomcat:tomcat01、tomcat02

image-20211028164152537

分别查看两个 tomcat 的网卡 ip 地址

image-20211028164342380

ping 相互的 ip 地址是可以通的

image-20211028164452120

但是 ping 容器的名字是不能 ping 通的

image-20211028164650404

  1. 使用 --link 进行连接

    再启动一个 tomcat03 容器,使用 --link 连接

docker run -d -p 8083:8080 --name tomcat03 --link tomcat01 tomcat

​ 测试是否能通过容器名 ping 通

​ 启动 tomcat03 可以 ping 通 tomcat01 通过容器名

image-20211028164937757

**注意:**相反 tomcat01 ping tomcat03 就会失败,正向连接可以,反向连接可能不可以

  1. 查看网卡的详细信息
docker network ls

docker inspect 上一条命令出来的id

image-20211028165440123

image-20211028165502149

可以看到为每一个启动的容器分配一个 ip

image-20211028165608409

  1. 反向 ping 不同的原因

tomcat03 在本地配置了 tomcat02 的配置

通过查看 tomcat03 容器的 hosts 文件可以看到

docker exec -it tomcat03 vim /etc/hosts
# 可以看到 tomcat03 的 hosts 中有 ip 地址和容器名的映射关系

image-20211028170050033

但是相反的是,在 tomcat01 的 hosts 文件中不能看到映射关系,所以 tomcat01 不能通过容器名 ping 通 tomcat03

--link 的操作其实就是在 hosts 配置配置了一个 ip 地址和 容器名 的映射关系,这种方式已经不再使用了。

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

10.3 自定义网络

通过命令 docker network ls 查看所有的 docker 网络

image-20211028170631560

网络模式:

  • bridge:桥接模式(默认)
  • none:不配置网络
  • host:主机模式,和服务器共享网络
  • container:容器内网络连通(局限性大)

构建自定义网络

# 直接启动的命令,默认是有一个 --net bridge,这个就是 docker0
docker run -d -P --name tomcat01 [--net bridge] tomcat

# docker0 特点:默认的,域名不能访问,使用 --link 可以实现互联
  1. 自定义一个网络
# --driver bridge	网络模式,桥接,默认也是 bridge
# --subnet 192.168.0.0/16	子网,可以包含 255*255 个子网
# --gateway 192.168.0.1		网关
# mynet		自定义网络的名字

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

image-20211028171446178

自己的网络就创建好了

image-20211028171726861

  1. 启动 tomcat 容器通过我们自己定义的网络
docker run -d -p 8081:8080 --name tomcat01 --net mynet tomcat
docker run -d -p 8082:8080 --name tomcat02 --net mynet tomcat

## 使用 docker inspect mynet 查看详细信息

image-20211028172216478

  1. 测试是否能 ping 通

    经过测试,通过 ip 地址和通过 容器名 都可以 ping 通

    现在不适用 --link 也可以 ping 通了

image-20211028172423556

我们自定义的网络 docker 都已经帮我们维护好了对应的关系,推荐使用自定义的网络

好处:

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

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

image-20211028172933178

10.4 网络连通

在上面创建了一个自定义的网络,网段是 192.168.0.0,docker0 自带的网段上 172.18.0.0

两个网段的是不能连通的

在 docker0 上有两个 tomcat 容器,mynet 上有两个 tomcat 容器,这两个网段的容器也是不能 ping 通的,所以需要 docker0 上的容器连接到 mynet 上,实现两个不同网段的容器互联。

image-20211028190342422

image-20211028191421044

image-20211028191502408

测试

tomcat01 容器连通 mynet 网络

docker network connect mynet tomcat01
docker inspect mynet	# 查看详细信息
# 下图我们可以发现,连通之后直接把 tomcat01 放到了 mynet 下
# 官网:一个容器两个ip地址 

image-20211028191723863

docker exec -it tomcat01 ping tomcat-net-01

image-20211028192105029

如果要跨网络操作别人,就需要使用 docker network connect 连通

11. 部署 Redis 集群

image-20211028192533953

  1. 创建一个 redis 的网卡
docker network create redis --subnet 172.38.0.0/16

image-20211028192811688

image-20211028192840290

  1. 通过脚本创建 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

image-20211028193411250

image-20211028193540551

  1. 启动 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 --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
done

image-20211028194258193

  1. 创建集群
docker exec -it redis-1 /bin/sh		# 进到 redis-1 节点里面

# 执行命令创建集群
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

image-20211028195815412

image-20211028195843124

image-20211028195953028

  1. 测试集群是否搭建成功

set a b 在集群中 set 一个值,显示的主机的 172.38.0.13 这个主机,然后使用命令 docker stop redis-3 停掉这个容器之后,在进入集群到 172.38.0.14 这个节点上,14 是 13 的从机,主机挂掉从机补上

image-20211028200420532

image-20211028200610550

docker 搭建 redis 集群完成。

12. Spring Boot 微服务打包 Docker 镜像

  1. 创建 Spring Boot 项目

    Controller 请求返回 Hello,Docker

  2. 打包应用

    把这个项目 package 打包成一个 jar 包,将这个 jar 包上传到 Linux 虚拟机上

image-20211028202508748

  1. 编写 Dockerfile
FROM java:8

COPY *.jar /app.jar

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

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]
  1. 构建镜像
docker build -t demo .

image-20211028202649768

image-20211028202955984

  1. 发布运行

image-20211028203140104

13. Docker Compose

13.1 介绍

官网:https://docs.docker.com/compose/

在上面的操作中,我们想要构建使用一个镜像的话需要进行:Dockerfile – build – run 手动操作,单个的容器。

如果说一个大的微服务项目中有成百个服务,并且的这些服务之间有着依赖关系,上面这种操作实现就会非常的繁琐。Docker Compose 就是用来进行轻松高校的管理容器,可以定义和运行多个容器。

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.

Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases.

Using Compose is basically a three-step process:

  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.
    • 通过 docker-compose.yml 配置文件来定义服务
    • 服务:容器、应用(web、mysql、redis …)
  3. Run docker compose up and the Docker compose command starts and runs your entire app. You can alternatively run docker-compose up using the docker-compose binary.
    • 启动项目

作用:批量容器编排

Compose 是 Docker 官方开源的项目,使用前需要进行安装。

Dokcerfile 可以让程序在任何地方运行,简化了运维的部署,假设有一个 web 服务,这个服务需要 多个容器:redis、mysql、nginx… 如果我们一个一个去 build 非常的麻烦。

可以写一个 Compose 批量把这些服务打包进来

version: "3.9"  # optional since v1.27.0
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
    links:
      - redis
  redis:
    image: redis
volumes:
  logvolume01: {}
  
# 在这个文件里面编排的容器,通过 docker-compose up 就可以一键启动
# 这些所有的服务运行起来就是一个完整的项目(一组关联的容器)
13.2 安装 Compose

官网地址:https://docs.docker.com/compose/install/

  1. 下载
# 官网的下载地址,非常的慢
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

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

image-20211028214137613

  1. 给文件授权
sudo chmod +x /usr/local/bin/docker-compose
  1. 确认安装成功
docker-compose version

image-20211028214338235

13.3 使用

官网:https://docs.docker.com/compose/gettingstarted/

官网案例:python应用,计数器,使用 redis 进行计数

  1. 创建一个应用

    就是创建一个目录

mkdir composetest
cd composetest
  1. 创建 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)
  • 创建一个需要的依赖包 requirements.txt
flask
redis
  1. 创建 Dockerfile 文件
# 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"]

#######################################################
# 上面的官网给出的例子,可能是版本的问题,执行失败,可以使用下面的内容
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python","app.py"]
# 从 python3.6 镜像开始构建镜像
# 将当前目录添加到 . / code 镜像中的路径
# 将工作目录设置为 /code
# 安装 python 的依项
# 将容器的默认命令设置为 python  app.py
  1. 创建一个 docker-compose.yml 文件
version: "3.9"
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"
    
#######################################################
# 上面的官网给出的例子,可能是版本的问题,执行失败,可以使用下面的内容
version: "3.8"
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
  redis:
    image: "redis:alpine"
# 从 Compose 文件定义了两个服务  web 和 redis
# 使用 Dockerfile 当前目录中构建的镜像
# 将容器上的公开端口  5000 转发到主机上的端口 5000.
# redis 服务使用从 Docker Hub 注册表中提取的公共 redis 镜像

image-20211028215358291

  1. 运行测试

    在有 docker-compose.yml 的文件夹下执行下面的命令

docker-compose up

启动成功,包括两个服务,web 和 redis

image-20211029094229779

流程:

  1. 创建网络
  2. 执行 Docker-compose.yml
  3. 启动服务,启动服务后可以看到创建了两个服务

在上面我们创建的文件名是 composetest,根据 docker-compose.yml 配置文件中的信息创建了两个服务

image-20211029094413452

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6yB7ydl-1635640517693)(D:\notes\Docker\Docker 知识点总结.assets\image-20211029094555117.png)]

image-20211029094951663

这些启动的服务的名字都是自动生成的,是一些默认规则。

启动之后是有两个服务的,可以使用 curl 访问得到返回值

image-20211029095114330

docker-compose 中的依赖全部帮我们下载了

image-20211029095218957

docker service ls
# 这个命令是查看集群中的服务,因为上面的例子不是集群的,所以会报错

image-20211029095354460

默认的服务名: 文件名 _ 服务名 _ num

假如有多个服务器,集群,我们的一个服务可能会在 A 服务器上运行,也可能在 B 服务器上运行

_num 表示的是一个副本数量。

假如我们需要运行 redis 服务,有 4 个副本

  1. 网络的规则

image-20211029100605410

项目中的内容都在同一个网络下,所以可以通过域名进行访问。

使用命令:docker network inspect composetest_default 可以查看网络信息的详情

image-20211029100814092

  1. 停止服务

快捷键:Ctrl + C

进入到 composetest 目录下执行命令:docker-compose down

image-20211029101152715

13.4 Compose 编写配置规则 yaml

官网地址:https://docs.docker.com/compose/compose-file/

Compose 的核心就是 docker-compose.yaml 配置文件

  • docker-compose.yaml 配置文件有 3 层
version: ''   # 版本 与 docker 引擎对应
services: # 服务
	服务1: web
		# 服务配置
		image
		build
		network
		......
	服务2: redis
		......
	......
# 其他配置 网络/卷、全局配置
volumes:
network:
configs:
......
  1. version

    版本信息根据官网给出的信息

image-20211029102627365

  1. services

image-20211029102656963

注意依赖这个配置信息

因为镜像的启动是有顺序的,假如上面的 web 需要先启动 redis

image-20211029102835950

13.5 使用 Compose 一键部署 WP bok

官网案例:https://docs.docker.com/samples/wordpress/

  1. 创建项目目录
  2. 编写 docker-compose.yml 配置文件
version: "3.9"
    
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
    volumes:
      - wordpress_data:/var/www/html
    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: {}
  wordpress_data: {}
  1. 启动
docker-compose up -d
  1. 查看
13.6 实战–构建自己的微服务
  1. 编写项目微服务
  2. Dockerfile 构建镜像
FROM java:8

COPY *.jar /app.jar

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

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]
  1. docker-compose.yaml编排项目
version: 3.9

services:
  lssapp:
    build: .
    image: lssapp
    depends_on:
      - redis
    ports:
      - "8080:8080"
  redis:
    image: "redis:alpine"
  1. 项目打包放到 linux 上
docker-compose up	# 启动

image-20211029110546813

  1. 启动测试

image-20211029111325496

image-20211029111343785

image-20211029111411998

如果项目需要重新构建可以使用这个命令 docker-compose up --build

14. Docker Swarm

14.1 环境搭建

在阿里云购买 4 台服务器用于做集群操作,选择按量收费就行

也可以在本地开 4 个虚拟机模拟集群操作

在 4 台服务器上安装 docker

image-20211029192508408

14.2 介绍

官网地址:https://docs.docker.com/engine/swarm/

工作模式:

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. 两个节点:管理节点、工作节点

操作都在 管理节点

image-20211029192628652

image-20211029193348824

image-20211029193515477

14.3 操作

image-20211029193756777

# 配置一下集群,将 docker01 节点成为一个主节点
# 初始化节点
docker swarm init --advertise-addr 192.168.253.155

# 初始完可以得到两个命令i
# 加入一个节点
docker swarm join
# 获取令牌,可以通过令牌让别的节点加入进来
docker swarm join-token manager
docker swarm join-token worker

image-20211029193900562

# 在 docker02 节点上执行命令,将节点加入 docker01,加入过去的就是一个 worker
docker swarm join --token SWMTKN-1-10kwelhmau8q2l45uqp8jep709ns2mlro1csndykeeigvkl0vx-873o4olo10103ctckdl2ppadh 192.168.253.155:2377

image-20211029195439582

# 在 docker01 主节点上执行命令,可以看到集群的节点信息
docker node ls

image-20211029195645649

将 docker03 加入集群并初始化为 manage;将 docker04 加入集群并初始化为 worker;

image-20211029200010728

集群搭建完成!!!

14.4 Raft 协议

上面的集群中搭建的两个主节点两个从节点,假设一个节点挂了,其他节点是否可用?

Raft 协议:保证大多数节点存活才可以用。

加入 docker01 节点宕机了,那么其他节点也都是不能使用了,包括另一个管理节点

image-20211029200723481

docker01 节点再次启动之后,我们发现 Leader 变成了 docker03 的节点

image-20211029200844232

# 使用命令离开一个节点
docker swarm leave

# 结果:Node left the swarm.

image-20211029201114525

将 docker02 节点也加入到管理节点,再次停掉管理节点 docker01 其他管理节点还是可以操作的,剩余两个管理节点

image-20211029201519372

image-20211029201559301

再次停掉一个管理节点,剩余一个管理节点,这种情况是没有办法使用的

image-20211029202301304

所以,为保证集群的可用性,有 3 个主节点,保证 > 1 台管理节点存活才能正常使用集群的操作(保证大多数节点存活才可以使用,高可用)

14.5 Swarm 集群弹性创建服务

弹性、扩缩容、集群

之前使用 docker-compose up 启动的一个项目也是单机的。

集群下面所有的东西都到了 swarm 里面,所有的东西都变成了 docker service。

容器 变成了 服务

假设 redis 需要启动三个,对于单体的来说就是启动了三个容器。

集群状态下,为了保证高可用,web 应用连接 redis,redis 有 3 台分布在不同的机器上,这个机器上不可能通过 ip 地址去访问,因为 ip 因为 docker 的ip地址会变化的,所以需要通过服务名来进行访问,这个集群就屏蔽了低等的节点的差异,只需要通过服务名就可以访问到集群。一个 redis 服务可能是好多个副本开启,假设一个挂掉了,其他的仍然可以使用。

image-20211029204240617

image-20211029204353417

操作

# 启动一个 nginx 的服务
docker service create  -p 8888:80 --name my-nginx nginx

################################
docker run  容器启动,不具有扩缩容
docker service 服务启动,具有扩缩容等

image-20211029204628628

查看服务,只启动一个容器,只有一个副本

image-20211029210356543

这一个的情况下,如果访问量特别大,一个服务可能扛不住,需要多开几个服务,所以要做到动态的扩容

动态扩缩容

# 为 my-nginx 服务创建 3 个副本(扩缩容)
docker service update --replicas 3 my-nginx
# 也可以用这个命令进行服务的扩缩容
docker service scale my-nginx=10

image-20211029211136199

image-20211029211803770

启动的多个副本分配到集群内的各个主机上,这些服务在集群中的任意的节点都可以进行访问。服务可以有多个副本,动态的扩缩容,实现高可用。

14.6 概念的总结

swarm:集群的管理和编排,docker 可以初始化一个 swarm 集群,其他节点可以加入。有管理和工作两个角色。

Node:就是一个 docker 的节点,多个节点就组成了一个网络的集群。有管理和工作两个角色

Service:就是一个任务,可以在管理节点或者工作节点来运行,是核心,用户可以访问。启动方式 docker service

Task:容器内的命令的,是一个细节的任务。在创建容器的时候是一层一层的

image-20211029213225266

image-20211029213302792

image-20211029213526110

命令 --> 管理 --> api --> 调度 --> 工作节点(创建 Task 容器维护创建)

服务副本与全局服务

​ 所有的节点都是分配的,管理节点和工作节点都可以跑项目

​ 项目可以分为全局运行和只能在副本上运行

​ 可以设置项目只在副本上运行和全局运行

image-20211029213856964

14.6.1 Docker Stack
# docker-compose 单机部署项目
docker-compose up -d wordpress.yml
# Docker Stack 部署---集群部署项目
docker stack deploy wordpress.yml

# docker-compose.yml 使用 stack
version: '3.4'
services:
  mongo:
    image: mongo
    restart: always
    networks: 
      - mongo_network
    deploy:
      restart_policy:
        condition: on-failure
      replicas: 2
  mongo-express: 
    image: mongo-express
    restart: always
    networks: 
      - mongo_network
    ports:
      - target: 8081
        published: 80
        protocol: tcp
        mode: ingress
    environment:
      ME_CONFIG_MONGODB_SERVER: mongo
      ME_CONFIG_MONGODB_PORT: 27017
    deploy:
      restart_policy:
        condition: on-failure
      replicas: 1
networks:
  mongo_network:
    external: true
14.6.2 Docker Secret

进行安全配置,配置密码、证书等…

image-20211029215325077

14.6.3 Docker Config

对容器进行统一的一些配置

image-20211029215358555

学习参考视频:https://www.bilibili.com/video/BV1og4y1q7M4?p=1

学习参考视频:https://www.bilibili.com/video/BV1kv411q7Qc?p=1

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值