Docker的使用


前言

可以简单的了解Docker使用,更多的话看官网文档学习
Docker安装:https://blog.csdn.net/weixin_43287895/article/details/126441251


一、Docker

1.简介

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

2.概述

应用目的:因为开发和上线作为两部分工作内容,这是因为环境配置的原因,有时候会发生开发正常而上线失败的情况,Docker就是为了解决应用环境和开发环境一致性的问题。
Docker可以实现发布项目的时候带着环境一起安装
Docker思想来自于集装箱
Docker核心思想:隔离,打包装箱,每个箱子是互相隔离的
通过隔离机制,将内存使用到极致,相对于虚拟机VM技术,十分的轻巧

3.虚拟机技术和Docker比较

虚拟机软件VMWare,openstack
虚拟机属于虚拟化技术,Docker容器技术也是虚拟化技术
两者相比较而言:

VM: linux centos原生镜像(一个电脑)!隔离,需要多个虚拟机几个G
Docker:隔离,镜像(最核心的环境,如linux开机关机4M,+jdk+mysql)十分的小巧,几M

虚拟机技术
每一次构造一个虚拟机都需要一个内核,十分的浪费资源
在这里插入图片描述
虚拟机技术缺点:

资源占用十分多

冗余步骤很多

启动很慢

容器化技术

容器化技术不是模拟一个完整的操作系统,他可以在所有容器中共享一个内核,避免了内核的重复构建,在这之上通过集装箱概念,将每一个容器中运行镜像并隔离,使得计算机的性能被极限使用。就好像一台计算机变成了多个计算机同时运行不同的服务
在这里插入图片描述

比较Docker和虚拟机技术不同:

传统虚拟机,虚拟出一条硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件
容器内的应用直接运行在宿主机的内容,容器没有自己的内核,所以就轻便了
每个容器间是互相隔离的,每个容器内都有一个属于自己的文件系统,互不影响

4.Docker官网

基于GO语言开发的,开源项目

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

文档:https://docs.docker.com/

仓库:https://hub.docker.com/

二、Docker构成

在这里插入图片描述
images镜像,build创建容器,pull拉取容器,run运行容器
镜像:image
docker镜像就好比是一个模板,可以通过这个模板来创建服务,如tomcat镜像---->run----->tomcat容器(提供服务)
通过这个镜像可以创建多个容器。最终服务运行就是在容器中的,这个容器是互相隔离的
容器:container
Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的
可以使用,启动,停止,删除,基本命令
容器可以简单的理解为一个简易的Linux系统
仓库:repository
仓库就是存放镜像的地方
仓库分为共有仓库和私有仓库
Docker Hub默认是国外的
阿里云 :容器服务,需要配置镜像加速

三、底层原理

1.docker如何工作的

Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Sokcet从客户端访问。

DockerServer接收到Docker-Client指令,就会执行这个命令

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ef0DEYdz-1661066303578)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220715224555029.png)]

2.docker为什么比虚拟机快

docker有比虚拟机更少的抽象层

docker利用的是宿主机的内核,VM需要Guest OS再搭建一个

所以新建一个容器的时候,不需要像虚拟机一样重新加载一个操作系统内核。而且docker速度比VM快

3.HelloWorld的启动

可以先运行官网的例子hello-world,就可以发现首先他会去找hello-world的image镜像,然后下载并运行出来

docker run hello-world

在这里插入图片描述
hello-world的过程
在这里插入图片描述

四、Docker命令

1. 帮助命令

docker version #显示docker版本信息
docker info # 显示docker系统信息
docker 命令 --help  # 万能命令

2. 镜像命令

docker images # 查看本地所有的镜像

[root@Test ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   9 months ago   13.3kB
# 解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像的创建时间
SIZE 镜像的大小
# 可选项
  -a, --all      # 列出所有的镜像       Show all images (default hides intermediate images) 
      --digests         Show digest
  -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 Only show image IDs

可以在docker hub中搜索镜像

2.1 docker search搜索镜像

docker search mysql

NAME                           DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                          MySQL is a widely used, open-source relation…   12877     [OK]       
mariadb                        MariaDB Server is a high performing open sou…   4935      [OK]       

# 可选项
  -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
--filter=STARS=3000 # 搜索出来的镜像大于3000
docker search mysql --filter=STARS=3000

[root@Test ~]# docker search mysql --filter=STARS=3000
NAME      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql     MySQL is a widely used, open-source relation…   12877     [OK]       
mariadb   MariaDB Server is a high performing open sou…   4935      [OK]  

2.2 docker pull下载镜像

# -----------------不指定版本
docker pull mysql
# docker pull 镜像名[:tag]
[root@Test ~]# docker pull mysql
Using default tag: latest # 如果不写tag,默认是最新版latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete # 分层下载layer。docker images 的核心。联合文件系统
93619dbc5b36: Pull complete 
99da31dd6142: Pull complete 
626033c43d70: Pull complete 
37d5d7efb64e: Pull complete 
ac563158d721: Pull complete 
d2ba16033dad: Pull complete 
688ba7d5c01a: Pull complete 
00e060b6d11d: Pull complete 
1c04857f594f: Pull complete 
4d7cfa90e6ea: Pull complete 
e0431212d27d: Pull complete 
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 #签名,防伪标志
Status: Downloaded newer image for mysql:latest 
docker.io/library/mysql:latest # 真实地址

#这两个命令是等价的
docker pull mysql
docker.io/library/mysql:latest
# ---------------指定版本
docker pull mysql:5.7

[root@Test ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists 
93619dbc5b36: Already exists 
99da31dd6142: Already exists 
626033c43d70: Already exists 
37d5d7efb64e: Already exists 
ac563158d721: Already exists 
d2ba16033dad: Already exists 
0ceb82207cd7: Pull complete #
37f2405cae96: Pull complete #
e2482e017e53: Pull complete #
70deed891d42: Pull complete #
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
# 也可以自己做一个镜像,保留

拥有一个非常重要的思想,联合文件系统,由两个不同版本的mysql可以看出,没下载过mysql的时候会通过分层文件,每一个都下载下来,但是当下载mysql5.7的时候,有些分层文件已经存在,就不会再重新下载了,只会下载不同的文件。极大的节省了内存

2.3 删除镜像

docker rmi 删除镜像

docker rmi -f +id或者名字 # -f是全部删除
docker rmi -f c20987f18b13
docker rmi -f $(docker images -aq) # docker images -aq查询所有镜像id,然后$递归传给前面的指令。可以完成批量删除

3.容器命令

有了镜像才能创建容器
在Linux中下载一个centos测试

docker pull centos # 下载镜像
docker ps #查看运行中的容器 

3.1 新建容器并启动

docker run [可选参数] image

#参数说明
	--name="Name" # 容器名字,用于区分容器
	-d 			  # 后台方式运行
	-it			  # 使用交互方式运行,进入容器查看内容
	-p		 	  # 小写,指定端口
		ip:主机端口:容器端口 
		主机端口:容器端口(常用)
		容器端口
	容器端口
	-P			  # 随机指定端口
# 测试
[root@Test ~]# docker run -it centos /bin/bash # 启动并进入容器。root后@主机名称值变化,容器内的很多命令都是不完善的
[root@197701580a6c /]# 
# 查看容器内的centos
[root@197701580a6c /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# 退出容器,但是退出容器会停止
exit 

在这里插入图片描述
在这里插入图片描述

最为明显的区别是颜色不一样

3.2 退出容器

exit # 退出容器会停止
Ctrl + p + q # 容器不停止,退出

3.3 删除容器

docker rm 容器id  #删除指定的容器,但是运行中的不能删除
docker rm -f 容器id #可以强制删除,包括运行中的
docker rm -f $(docker ps -aq) # 递归删除,删除所有容器
docker -a -q |xargs docker rm # 删除所有容器

3.4启动和停止容器

docker start 容器id 	#启动容器,新建后的容器,哪怕停止了也会存在,但是ps不会显示,-a可以,可以用start重新启动
docker restart 容器id #重启容器
docker stop 容器id	#停止当前运行的容器
docker kill 容器id	#强制停止当前容器

4. 常用的其他命令

4.1 后台启动容器

docker run -d centos 
# 通过-d的方式会出现centos停止了,docker容器使用后台运行,必须要有一个前台进程,docker发现没有前台应用就会自动停止

4.2 查看日志

docker logs 
	-f
	-t
docker logs -f -t -tail 10 容器 # 显示10条
docker logs -f -t  容器 # 显示全部

4.3 查看容器中的进程信息

top命令
docker top 容器ID # 查看容器中进程信息

4.4 查看镜像元数据

docker inspect 
	-f
	-s
docker inspect 容器ID
# ps所得到的容器ID,是元数据中,ID的前一部分

4.5 进入当前正在运行的容器

#容器一般都是使用后台方式运行,需要进入容器,修改配置
# 方式1
# 会重新打开一个命令行
docker exec -it 容器id bashshell
docker exec -it id /bin/bash

# 方式2
# 会进入正在执行的代码,也就是说,如果里面有一个死循环,会一直看到死循环
docker attach 容器id

# 差别
docker exec # 进入容器后会开启一个新的终端,可以在里面操作
docker attach # 进入容器后不会开启一个新的终端。不会启动新进程

4.6 从容器内拷贝文件到主机上

docker cp 容器ID:容器内路径 目的主机路径
docker cp id:/home/test.java /home

# 这样的拷贝是一个手动过程,可以用-v卷技术,自动同步

5.小结

在这里插入图片描述

五、Docker镜像

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

如何得到镜像:从远程仓库下载,朋友拷贝,自己制作一个镜像DockerFile

1. UnionFS联合文件系统

UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下

简单来讲,就是每次修改后,会生成一个记录,如第一次为1,第二次为2,然后如果想要版本更新,一共6个文件,发现前3个文件没有改动,那么就会下载剩下改动的3个文件。

再举一个例子,如果tomcat下载需要linux内核,jdk下载也需要linux内核,那么下载tomcat后,jdk就不需要下载linux内核了

2.Docker镜像加速原理

Docker的镜像是由一层一层的文件系统构成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel。Linux刚启动时会加载boofs文件系统,在Dokcer镜像的最底层是bootfs。当加载成功后,系统运行起来,内存的使用权会由bootfs转交给内核,此时系统也会卸载bootfs

rootfs(root file system)在bootfs上面,包含的是典型的Linux系统的/dev、/proc、/bin、/etc等标准目录和文件

rootfs就是各种不同操作系统的发行版,如Ubuntu,Centos

3. 为什么Docker的OS镜像非常小

对于一个精简的OS,rooftf可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用host主机的kernel。自己只需要rootfs。可以看出不同版本的linux系统。内核是一样的,只有rootfs有差别

六、 分层理解

下载镜像的时候,会一层一层的下载

所有的Docker镜像都起始于一个基础镜像层,当进行修改或者增加新的内容时候,就会在当前的镜像层之上,创建新的镜像层
在这里插入图片描述

也就是说,docker的镜像,通过层级概念来生成的,
在这里插入图片描述
如第一层centos作为一个文件,mysql第二个,tomcat第三个

第二层redis,app1.0,es

第三层,修改app1.0为2.0

修改的文件会直接覆盖,所以一共还是6个文件

生成镜像的时候对外是一个文件,但是内部是6个文件分层下载

Docker镜像都是只读的,当容器启动的时候,一个新的可写层被加载到镜像的顶部,这一层就是容器层,以下都是镜像层,镜像层不能变动

也就是说,一个镜像被pull,假设这个镜像有6个层级,他会在下载的时候,下载6个文件,当你的镜像中拥有相同的文件时候,他会略过,来节省资源。当镜像被运行的时候,会生成一个镜像层,镜像层中包含这6个文件,之后生成一个容器层,这就是我们来进行修改的层级,我们的修改都在容器层,镜像层是不能被修改的,是只读的,当我们想要将我们run的容器,打包发给其他人的时候,docker会把容器层和镜像层打包成一个层级,将修改的部分进行覆盖,生成一个新的镜像,来发给其他人。而别人运行镜像的时候,也会将我们修改后的,生成一个镜像层,只读,而他们在容器层,修改。

七、 Commit镜像

docker commit # 提交容器为一个新的副本
# 命令与git相似
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]

# 以tomcat为例
# 运行tomcat
docker run -d -p 8080:8080 tomcat:9.0
docker exec -it id /bin/bash
cp -r webapps.list/* webapps
exit
# 生成自己的镜像
docker commit -a="hang" -m="webapp add" id tomcat02:1.0

八、 容器数据卷

解决数据在容器的问题

数据存储在本地,而不是容器

容器之间数据共享的技术,Docker容器中的数据,同步到本地

目录的挂载,将容器内的目录挂载到Linux上

在这里插入图片描述

容器的持久化和同步操作,容器间的也是可以数据共享的

1.使用数据卷

方式1:直接使用命令挂载 -v
docker run -d -v 主机目录地址:容器内目录地址
# 在主机上运行,查看是否挂载
docker inspect 容器id
# 在mounts的内容,为挂载内容

若容器停止,数据在linux修改,也会同步过去

2.例子Mysql安装

mysql的数据放在data目录

# 下载
docker pull mysql:8.0
# 运行容器
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name=mysql01 mysql:8.0
# mysql需要配置密码的,
# 8.0后安装策略不一样mysql8之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password
docker exec -it id /bin/bash
mysql -uroot -p
123456
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
# 就可以用可视化软件连接了
# 在linux的home/mysql就可以看到对应的文件了
##----------------------
# 属于匿名目录

3.具名挂载和匿名挂在

建议使用具名挂载

# 匿名挂载
-v 容器内路径!-P 随机端口映射
docker run -d -P --name nginx01 -v /etc/nginx nginx
docker volume
	create
	inspect
	ls			# 查看本地所有数据卷
	prune
	rm
docker run -d -P --name nginx01 -v /etc/nginx nginx
docker volume ls
# -v的时候没有写容器内的路径,没有写容器外的路径,都是一串

在这里插入图片描述

一串的都是匿名的

# 具名挂载
docker run -d -P --name nginx02 -v jumingnginx:/etc/nginx nginx
docker volume ls

在这里插入图片描述

docker inspect jumingnginx

在这里插入图片描述

所有的docker容器内的卷,没有指定目录下都在

/var/lib/docker/volume/xxxx/_data

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

拓展

docker run -d -P --name nginx02 -v jumingnginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v jumingnginx:/etc/nginx:rw nginx
# 在容器内路径后面加入了:ro或者rw
# 可以通过-v 容器内路径:ro或rw,可以改变读写权限
# ro       :read only  只读		只能从宿主机改变,内部无法改变
# rw	   :read write 可读可写
# 一旦这个设置了容器权限,容器对我们挂载出来的内容就有限定了

九、DockerFile

DockerFile就是用来构建docker镜像的构建文件

是一段命令脚本

# 创建dockerfile文件
vim dockerfile1
#  内容--------
FROM centos

VOLUME["volume01","volume01"]

CMD echo "------end------"
CMD /bin/bash
# 这里是匿名挂载
# 这里的每个命令,就是镜像的一层
# -------
docker build -f /home/docker-test-volume/dockerfile1 -t hang/centos:1.0 .

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUCz9kXW-1661068091101)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220719212531138.png)]

# 进入自己的镜像
docker run -it id /bin/bash
# 在volume01创建volume01.txt
cd /volume01
touch volume01.txt

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c3Q6VROV-1661068091102)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220719212845245.png)]

# 可以通过查看运行中的容器,看id
docker ps
# 然后通过id,来查看元数据
docker inspect id
# 发现volume01,volume02匿名挂载在docker的目录下

在这里插入图片描述
在这里插入图片描述

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

1.数据卷容器:容器间同步

多个mysql同步数据,

在这里插入图片描述

# 创建自己的镜像,命名为docker01
docker run -it --name=docker01 自己的镜像id
# 将docker02与docker01 的数据卷同步
docker run -it --name docker02 --volumes-from docker01 自己的镜像id
# 创建一个文件在volume01,test01
# 可以发现docker02的volume01中也有test01

大概意思为,创建了docker01的容器并挂载数据卷,然后用继承的方式,docker02就是docker01的子容器,并挂载相同的数据卷

也就是说,我们将第一个容器,挂载了数据卷在主机上,然后创建第二个容器作为子容器继承第一个容器的数据卷,那么就有2个容器都挂载了相同的数据卷

这是一种备份机制

2.DockerFile构建

构建步骤

  1. 编写一个dockerfile文件
  2. docker build 构建成为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(docker hub 或者阿里云)

从docker hub上的centos镜像中,可以跳转一个github网站,他是一个DockerFile脚本

FROM scratch
ADD centos-7-x86_64-docker.tar.xz /

LABEL \
    org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20201113" \
    org.opencontainers.image.title="CentOS Base Image" \
    org.opencontainers.image.vendor="CentOS" \
    org.opencontainers.image.licenses="GPL-2.0-only" \
    org.opencontainers.image.created="2020-11-13 00:00:00+00:00"

CMD ["/bin/bash"]

2.1指令

基础

  1. 每个保留关键字,都必须是大写字母
  2. 执行执行从上到下执行的
  3. # 表示注释
  4. 每一个指令都会创建提交一个新的镜像层,并提交
  5. dockerfile是面向开发的,发布项目,做镜像就需要编写dockerfile文件
  6. 企业交付的标准

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

DockerImages:通过DockerFile构建生成的镜像,最终要发布运行的产品,原来是jar包或者war包

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

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

2.2测试

Docker Hub 大部分都是从基础镜像FROM scratch

# 编写dockerfile文件
FROM centos:7
MAINTAINER hang<772781425@qq.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
# 构建镜像
docker build -f mydockerfile-centos -t mycentos:1.0 .
# 测试运行
docker run -it 容器id
# 测试
可以使用vim和ipconfig,而且默认目录为/usr/local

拿到一个镜像,可以用history查看是怎么构建的

docker history 镜像id

3.CMD和ENTRYPOINT区别

CMD

# CMD
# 编写dockerfile
FROM centos:7
CMD ["ls","-a"]
# 构建镜像
docker build -f cmd-test -t mycmd-test:1.0 .
# 进入镜像
docker run -it mycmd-test:1.0
发现只会打印ls -a,并不会有命令行等操作
# 若进行追加命令操作
docker run -it mycmd-test:1.0 -l
则会发生错误
因为他会进行命令的替换
最后一行是CMD ["ls","-a"],ls -a替换后为 -l
-l不是命令,所以报错
如果想要执行
docker run -it mycmd-test:1.0 ls -al

ENTRYPOINT

# ENTRYPOINT
# 编写dockerfile文件
FROM centos:7
CMD ["ls","-a"]
# 构架镜像文件
docker build -f cmd-entrypoint -t entrypoint-test:1.0 .
# 运行镜像
docker run -it 镜像id
发现会打印ls -a
# 进行追加命令操作
docker run -it 镜像id -l
发现可以执行

4.Tomcat镜像

# 准备镜像文件,tomcat和jdk
# 编写dockerFile文件,官方命名Dockerfile,build会自动寻找这个文件,就不需要-f指定了
touch readme.txt
vim Dockerfile
# 编写dockerfile文件
FROM centos:7

MAINTAINER hang<77281425@qq.com>
COPY readme.txt /usr/local/readme.txt

ADD jdk-8u221-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.64.tar.gz /usr/local/

RUN yum -y install vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_221
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.64
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.64
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:$CATALINA_HOME/lib
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.64/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.64/logs/catalina.out
# 构建镜像
docker build -t mydirtomcat .
# 运行镜像
docker run -it --name mydiytomcat -p 3344:8080 -v /home/myDir/build/tomcat/test:/usr/local/apache-tomcat-9.0.64/webapps/test -v /home/myDir/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.64/logs be3bd5df7
# 部署一个小网站
cd test
mkdir WEB-INF
cd WEB-INF
vim web.xml
# web.xml



<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    
</web-app>



# 创建一个jsp
cd ..
vim index.jsp

# 页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<font color=red>Hello World</font>
</body>
</html>
# 在3344端口运行即可
:3344/test

5.发布镜像

5.1到Docker Hub

需要在docker hub上注册自己的账户

docker login -u 账号

# 上传镜像
docker pull 用户名/镜像:版本号
denied是被拒绝,看看有什么错误,用户名得是自己的用户名
# 添加版本号
docker tag 镜像id 用户名/镜像:版本号

5.2到阿里云

登录阿里云

找到容器镜像服务

创建命名空间

创建容器镜像

点击镜像仓库

按照步骤一步一步做就行了

# 需要注意的是
需要docker tag
docker tag be3bd5df781e registry.cn-beijing.aliyuncs.com/squid/test:0.1-tomcat

6.小结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xp0F2m7v-1661068091107)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220720174113116.png)]

十、Docker网络原理

1.Docker0

# 获取IP地址
ip addr

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XTLB4nqx-1661068091110)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220720175442512.png)]

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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:16:3e:08:cc:98 brd ff:ff:ff:ff:ff:ff
    inet 172.28.141.20/20 brd 172.28.143.255 scope global dynamic eth0
       valid_lft 314532066sec preferred_lft 314532066sec
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:f1:34:67:6c brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
18: br-bf40d2407017: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:e7:d3:c0:32 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-bf40d2407017
       valid_lft forever preferred_lft forever

三个网络

docker 是如何处理容器网络访问的
# 
docker run -d -P 3344:8080 --name tomcat01 tomcat
# 因为最新版的tomcat不具备net-tools
# 进入容器后,执行
apt update && apt install -y iproute2
# 查看ip地址
docker exec -it tomcat01 ip addr

# 
[root@Test WEB-INF]# docker exec -it tomcat01 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
99: eth0@if100: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# @if100
对应了容器外的地址
# Linux能不能ping通这个网络
ping 172.17.0.2 
发现可以
# Linux可以ping通容器内部
192.168.0.1 路由器地址
192.168.0.3 在同一个网段,同一个网段是可以ping通的

原理

每启动一个docker容器,docker就会给容器一个ip ,只要安装了docker,就会有一个默认的网卡docker0

使用的是桥接模式,使用的是evth-pair技术

# 重新ip addr
# 发现多出一个地址
100: vetha1763d3@if99: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether d2:ba:d0:14:d9:c2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
# vetha
# @if99 
对应了容器的地址
# 每次新建一个容器,就会出现一对网卡

这样出现一对对网卡的技术就是evth-pair技术

# evth-pair 就是成对的虚拟设备接口。他们都是成对出现的,一段连着协议,一段彼此相连
# 正因为有这个特性,evth-pair技术充当一个桥梁,连接各种虚拟网络设备的
# openstack,docker容器之前的连接,OVS的连接,都是使用evth-pair技术

测试

tomat01和tomcat02 是否ping通

docker exec -it tomcat02 ping 172.17.0.2 # 是tomcat01的地址
可以ping通

结论,容器和容器之间是可以ping通的

在这里插入图片描述
在这里插入图片描述

Docker使用的是Linux桥接,宿主机中是一个Docker容器的网桥docker0。docker中的所有网络接口都是虚拟的,虚拟的转发效率高。

删除容器后,对应的网桥网段就会消失

2.容器互联–link(不推荐)

解决通过容器名字来进行访问容器

docker exec -it tomcat02 ping tomcat01
# ping不通
# 如何解决通过容器名字访问
# 通过--link解决容器网络连通
docker run -d -P --name tomcat03 --link tomcat02 tomcat
docker exec -it tomcat03 ping tomcat02
# 但是反向不能ping通
docker exec -it tomcat02 ping tomcat03
失败
# 可以通过inspect 研究具体的网络情况
docker network ls
# 找到docker0的network ID
docker network inspect ID
# 可以查看hosts内容,来看配置信息
docker exec -it tomcat03 cat /ect/hosts

–link 就是在hosts配置中加入一个写死的tomcat02地址和id

3.自定义网络(推荐)

3.1docker0的问题

不支持容器名进行连接访问,但是如果自己自定义网络就可以实现容器的互联

3.2网络模式

bridge:桥接模式 (默认)
none : 不配置网络(一般不用)
host : 与宿主机共享网络
container : 容器内网络连通(不建议,局限很大)

3.3测试

# 直接启动的命令,会自动默认带上--net bridge,这个是docker0
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点:默认,域名不可访问,--link可以访问
# 自定义网络 --driver bridge 网桥模式 --subnet 子网 --gateway 网关
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

#创建两个在自己网络的容器
docker run -d -P --name tomcat01 --net mynet tomcat
docker run -d -P --name tomcat02 --net mynet tomcat
# 查看网络,可以看出自己网络有两个挂载的容器
docker network inspect mynet
# 进入虚拟机,安装ping命令
apt install -y inetutils-ping
# 之后就可以2个tomcat,ping成功,通过服务名
docker exec -it tomcat01 ping tomcat02
# 就可以不使用--link

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

好处:

不同的集群使用不同的网络,保证网络的健康

如mysql,一个网络192.160.0.0 redis网络192.161.0.0,两个网络互不影响,

在这里插入图片描述

两个容器是隔离的

4.网络连通

解决容器网络隔离的问题

在这里插入图片描述

网络之间是无法打通的,但是容器和网络之间是可以连通的

# 在docker0上运行2个容器
docker run -d -P --name tomcat-docker0-1 tomcat
docker run -d -P --name tomcat-docker0-2 tomcat
# ping之前在mynet的上的tomcat
docker exec -it tomcat-docker0-1 ping tomcat01
# 发现失败,因为在不同的网段,而且容器间相互隔离
# 解决方法,打通两个容器间的网络
docker network connect 网络 容器名
docker network connect mynet tomcat-docker0-1
# 查看network inspect mynet
docker network inspect mynet
# 发现tomcat-docker0-1 容器挂载到了mynet的网络下
#一个容器  两个ip

假设呀跨网络操作别人,就要用docker network connect 连通

5.Redis集群

在这里插入图片描述

# 建立redis网卡
docker network create redis --subnet 172.38.0.0/16
# 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
# 运行
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.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

docker run -p 6372:6379 -p 16372:16379 --name redis-2 -v /mydata/redis/node-2/data:/data -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

docker run -p 6373:6379 -p 16373:16379 --name redis-3 -v /mydata/redis/node-3/data:/data -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

docker run -p 6374:6379 -p 16374:16379 --name redis-4 -v /mydata/redis/node-4/data:/data -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

docker run -p 6375:6379 -p 16375:16379 --name redis-5 -v /mydata/redis/node-5/data:/data -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

docker run -p 6376:6379 -p 16376:16379 --name redis-6 -v /mydata/redis/node-6/data:/data -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
# 创建集群,redis只有sh,没有bash
docker exec -it redis-1 /bin/sh
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
# 测试
redis-cli -c
cluster info
cluster nodes
# 测试高可用,放入a 的值为b
set a b
# 停用被分配到的redis
docker stop 被分配到的redis
get a
# 等待选举完毕后,仍旧可以得到值b
cluster nodes
# 可以看出 被分配到的redis fail,崩溃,他的从机变为master

十一、Docker Compose

Docker Compose解决微服务过多,依赖关系过于复杂。

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

步骤

dockerfile

docker-compose yml

run docker-compose up

作用:批量容器编排

Compose是Docker的开源项目,需要安装

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

服务services,容器,应用等,打包成一个项目project成为一个项目

1.安装Compose

# 下载安装
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
# 下载到了/usr/local/bin/docker-compose
# 授权
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
# 为所有用户授权,可挑选一个执行
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
# 查看是否安装成功
docker compose version

2.测试

1.应用 app.py

2.Dockerfile 应用打包为镜像

3.Docker-compose yaml,定义整个服务,需要的环境,web、redis

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

# 1
mkdir composetest
cd composetest
# 2   app.py
vim app.py
# 3
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)
# 4   requirements.txt
vim requirements.txt
# 5
flask
redis
# 6  Dockerfile
vim Dockerfile
# 7
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"]
# 8  docker-compose.yml
vim docker-compose.yml
# 9
version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"
# 10
docker compose up
# 11 因为没有建立什么东西的原因,需要build一下,看日志可发现

# 12
docker compose up

可以使用curl localhost:5000测试一下,查看是否正常

3.流程

1、创建网络

2、执行Docker-compose.yml

3、启动服务

启动了2个composetest-web-1,composetest-redis-1

因为

1、文件名为composetest

2、定义了2个服务,web,redis

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

3.1自动的默认规则

docker images,发现web,redis和python都被创建了镜像

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

多个服务器,集群,A,B ,_num 是副本数量

网络规则

docker network ls

生成一个自己的网络composetest_default,而且生成的容器在这个网络下

在同一个网络下,可以用域名访问

3.2停止

docker-compose down

Ctrl+C

3.3yaml规则

docker-compose.yml核心

# 3层
version: '' # 版本第一层	
services:   # 服务第二层
	服务1: web
		# 服务配置
		images
		build
		network
	服务2:redis
# 其他配置 第三层
# 网络配置,卷、全局规则
volumes
networks
configs
# depends_on
启动顺序的保证
如需要先启动redis,在启动web
web              3
	depends_on:
		- redis  1
		- db     2
# deploy
与集群相关
	# replicas
		副本

十二、 Docker Swarm

集群方式部署

需要4台服务器

右键xshell栏目可以选择发送输入到所有会话

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oZS7Tvt1-1661068124796)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722184116479.png)]

managers管理worker节点,managers至少有3个

1. 搭建集群

安装docker

# 1 
--advertise-addr string
私网
公网
ip addr
eth0:的ip地址就是私网ip
# 成为工作节点
docker swarm init --advertise-addr 172.16.110.37

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ymT5cnk3-1661068124797)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722191139938.png)]

得到两个命令:

    docker swarm join --token SWMTKN-1-2bfu00ntnw5czorap0yl5tscj4neztno23rqq6dh4ma1ckp1ib-4zuarxbbqdbbtzq2lpz751o1x 172.16.110.37:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

docker swarm join # 加入一个节点
# 获取令牌
docker swarm join-token manager
docker swarm join-token worker

docker02,作为了一个工作节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q99iyVm7-1661068124798)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722191403995.png)]

在docker01上

docker node ls # 可以查看存在节点

docker03,作为了一个工作节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mz5EgERc-1661068124798)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722191637032.png)]

docker04,作为一个manager节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZDhvzUwS-1661068124799)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722191741175.png)]

docker node ls

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cvS3pnse-1661068124799)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722191813657.png)]

可以发现manager节点为reachable,worker节点为空,第一个节点为leader

目前是双主双从

2.Raft一致性算法

如果一个节点挂了,其他节点是否能用

Raft协议:保证大多数节点存活才可以用。至少大于1,集群的话至少大于3

如果docker01节点关闭了docker,相当于宕机

目前是双主双从,另外一个主节点也不能使用了

如果docker01重新启动,那么就又可以用了

但是docker01从leader,变成 了Reachable,虽然也是manager节点,但是不是leader了,leader变成了docker04

如果docker03,离开了集群,docker swarm leave

docker node ls

docker03的状态status,会变成down

将docker03变成manager节点

worker从节点没有命令,只有manager才能使用命令

现在是三主一从

将docker01关闭,systemctl stop docker

在docker04中再次docker node ls

发现docker01节点的status变化为Unreachable

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-epH31v6v-1661068124800)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722193303018.png)]

其他节点还能继续使用

若关闭节点docker04,那么仍旧还会像两主两从的情况,无法使用,会报错

所以至少要3个主节点,>1台管理存活

3. 体会

弹性、扩缩容、集群

docker-compose 也是一个单机

集群:swarm节点,所有东西变成docker service

集群:3台redis,分布在不同的机器上

容器—服务----副本

redis服务----有10个副本(同时开启10redis)

docker service
包含创建、动态扩展服务、动态更新服务

灰度发布:金丝雀发布:升级不影响服务

升级项目方式:停止或者404,

docker service create -p 3344:80 --name mynginx nginx
docker run 容器启动、不具备扩缩容
docker service 服务、具备扩缩容,可以滚动更新,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LI8ijSg5-1661068124800)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722194841132.png)]

replicas副本,目前只有一个

通过
docker ps 
在四台服务器上寻找,发现在docker03启动的nginx,而不是docker01

如果压力很大,一个服务器撑不住

docker service update --replicas 3 mynginx

在这里插入图片描述

发现replicas的个数变为3

通过外网进行访问,发现,如果在没有nginx的服务器网址上运行3344端口,也可以访问到nginx。

因为容器间的隔离,所以也可以直接扩10个

# 想要将扩的nginx服务关闭,即可
docker service update --replicas 1 mynginx

这就是动态扩缩容

# 也可以通过scale来进行扩缩容,是一样的效果
docker service scale mynginx=5
# 5份,和update一样

4. 总结

swarm

集群的管理和编排,docker可以初始化init一个swarm集群,一个是管理员manager和worker节点

node

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

Service

服务,可以在管理节点或者工作节点来运行。核心

Task

容器内的命令,细节任务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B7Enx7F4-1661068124802)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722201046096.png)]

命令—manager----api----调度-----工作节点(创建容器task)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gu6luI76-1661068124803)(C:\Users\77278\AppData\Roaming\Typora\typora-user-images\image-20220722201604166.png)]

全局服务和副本服务

启动的服务在全局随机节点运行,还是只能在工作节点运行

--mode
# 默认是replicated
docker service create --mode replicated --name mytom tomcat:7
docker service create --mode global --name mytom tomcat:7

网络模式:

Swarm

ingress:特殊的overlay,具有负载均衡的功能,IPVS,VIP

Overlay:多台电脑加入到overlay网络,本来每个电脑是ping不通的,但是加入了这个网络后就能ping通

刚才的集群模式,虽然docker在4个机器上,但是却是同一个网络ingress网络,

十三、Docker Stack

docker-compose单机部署项目

docker stack 部署,集群部署

# 单机
docker compose up -d workpress.yml
# 集群
docker stack deploy workpress.yml

十四、Docker Secret

安全

配置密码、加密、证书

docker secret 

十五、Docker Config

配置

docker config
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值