文章目录
前言
可以简单的了解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语言开发的,开源项目
二、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指令,就会执行这个命令
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 .
# 进入自己的镜像
docker run -it id /bin/bash
# 在volume01创建volume01.txt
cd /volume01
touch volume01.txt
# 可以通过查看运行中的容器,看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构建
构建步骤
- 编写一个dockerfile文件
- docker build 构建成为一个镜像
- docker run 运行镜像
- 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指令
基础
- 每个保留关键字,都必须是大写字母
- 执行执行从上到下执行的
#
表示注释- 每一个指令都会创建提交一个新的镜像层,并提交
- dockerfile是面向开发的,发布项目,做镜像就需要编写dockerfile文件
- 企业交付的标准
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.小结
十、Docker网络原理
1.Docker0
# 获取IP地址
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
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栏目可以选择发送输入到所有会话
managers管理worker节点,managers至少有3个
1. 搭建集群
安装docker
# 1
--advertise-addr string
私网
公网
ip addr
eth0:的ip地址就是私网ip
# 成为工作节点
docker swarm init --advertise-addr 172.16.110.37
得到两个命令:
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,作为了一个工作节点
在docker01上
docker node ls # 可以查看存在节点
docker03,作为了一个工作节点
docker04,作为一个manager节点
docker node ls
可以发现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
其他节点还能继续使用
若关闭节点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 服务、具备扩缩容,可以滚动更新,
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
容器内的命令,细节任务
命令—manager----api----调度-----工作节点(创建容器task)
全局服务和副本服务
启动的服务在全局随机节点运行,还是只能在工作节点运行
--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