1.概述
一句话,带着你的开发环境一起上线,避免了别人机器上无法运行的问题
docker不是一个完整的系统,只有部分核心
DevOps(开发运维一体)
应用更快速的交付和部署
传统:一对帮助文档,安装程序。
Docker:打包镜像发布测试一键运行。
更便捷的升级和扩缩容
使用了 Docker之后,我们部署应用就和搭积木一样
项目打包为一个镜像,扩展服务器A!服务器B
更简单的系统运维
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨
到极致。
Docker的基本组成
- 镜像(image):
docker镜像就好比是一个目标,可以通过这个目标来创建容器服务,tomcat镜像==>run==>容器(提
供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)。 - 容器(container):
Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的.
启动,停止,删除,基本命令
目前就可以把这个容器理解为就是一个简易的 Linux系统。 - 仓库(repository):
仓库就是存放镜像的地方!
仓库分为公有仓库和私有仓库。(很类似git)
Docker Hub是国外的。
阿里云…都有容器服务器(配置镜像加速!)
2.安装Docker快速起步
安装Docker
环境准备
Linux要求内核3.0以上
所以我们先查看一下系统内核
uname -r
直接去官网安装
https://docs.docker.com/engine/install/
卸载旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
安装操作
需要的安装包
yum install -y yum-utils
设置镜像的仓库
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
安装docker相关的 docker-ce 社区版 而ee是企业版
yum install docker-ce docker-ce-cli containerd.io
启动docker,这一步非常重要
systemctl start docker
使用docker version查看是否按照成功
docker version
测试
docker run hello-world
顺利启动
镜像加速器
还可以再快一点,找到阿里云镜像加速器
阿里云镜像加速器
3.Run流程和Docker原理
Run流程
我们自定义个镜像拉取一下吧(拉取一个不存在的镜像肯定报错)
docker run 镜像名称
原理
docker容器是一个非常小的核心
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socket从客户端访问
Docker-Server接收到Docker-Client的指令,就会执行这个命令!
Docker比虚拟机快的原因
1、docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
2、docker利用的是宿主机的内核,而不需要Guest OS。GuestOS: VM(虚拟机)里的的系统(OS);HostOS:物理机里的系统(OS);
少了重复的操作系统部分,就会好很多
因此,当新建一个 容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。然而避免引导、加载操作系统内核是个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载GuestOS,返个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个复杂的过程,因此新建一个docker容器只需要几秒钟。
4.docker常用命令
帮助命令
docker version 查看版本
docker info 查看docker系统信息
docker --help 万能命令,查看所有命令信息
镜像命令
docker images #查看所有本地主机上的镜像 可以使用docker image ls代替
docker search 镜像名称 #搜索镜像
docker pull 镜像名称 或者 docker image pull #下载镜像
docker rmi 或者 docker image rm # 删除镜像
docker pull 下载镜像
docker images 查看所有本地的主机上的镜像
docker rmi 删除镜像
镜像命令到此为止,具体如何操作是容器命令的事情,剩下的是容器命令来操作镜像,这一切的前提是有一个Linux的镜像来操作这些
5.容器命令
说明:我们有了镜像才可以创建容器,Linux,下载centos镜像来学习
必须先拉取一个Linux的系统镜像
参数说明
docker run [可选参数] image | docker container run [可选参数] image
可选参数:
--name="Name" 容器名字 tomcat01 tomcat02 用来区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 8080(宿主机):8080(容器)
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口 容器端口
-P(大写) 随机指定端口
运行centos
注意,现在是在centos内部,我们可以运行linux命令查看,centos内部和linux一样,一应俱全
退出的操作:exit命令(这是关闭退出)或者Ctrl+P+Q (这是保持运行退出)
列出运行状态的容器
docker ps 命令
命令如下:
默认 列出当前正在运行的容器
docker ps -a 列出所有运行的容器,包括以前运行过的
docker ps -n=? 根据n来显示最近运行的容器,1是最新的2、3、4、5....以此类推
docker ps -q 显示容器运行的编号
也可以搭配起来整活,-aq显示所有运行的编号,随意搭配吧
docker ps -aq
删除容器
docker rm 容器id #删除指定的容器,不能删除正在运行的容器,如果要强制删除 rm -rf
docker rm -f $(docker ps -aq) #删除指定的容器
docker ps -a -q|xargs docker rm #删除所有的容器(linux管道符操作)
启停容器
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前正在运行的容器
docker stop $(docker ps -qa) #停掉当前正在运行的全部容器
docker kill 容器id #强制停止当前容器
Docker Run和Docker Start的区别
docker中run和start的区别
docker run 后面指定的是一个镜像
docker start指定的是一个容器
docker run是利用镜像生成容器,并启动容器,而docker start是启动一个之前生成过的容器
常用其他命令
后台启动容器
docker run -d 镜像名称
# 问题docker ps. 发现centos 停止了
# 常见的坑,docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
查看日志
docker logs --help
-tf #显示日志信息(一直更新) --tail number #需要显示日志条数
docker logs -t --tail n 容器id #查看n行日志
docker logs -ft 容器id #跟着日志
查看容器中的进程
docker top 容器id
查看镜像的元数据
# 命令 docker inspect 容器id
#测试 ➜ ~ docker inspect 55321bcae33d
[
{
"Id": "55321bcae33d15da8280bcac1d2bc1141d213bcc8f8e792edfd832ff61ae5066",
"Created": "2020-05-15T05:22:05.515909071Z",
"Path": "/bin/sh", ...
}
]
进入容器
以交互模式进入当前正在运行的容器
方式一
docker exec进入当前容器后开启一个新的终端,可以在里面操作。(常用)
# 命令
docker exec -it 容器id bashshell
# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
方式二
docker attach 进入容器正在执行的终端
docker attach 容器id
docker attach 55321bcae33d
将docker容器中centos里的文件拷贝到linux中
命令:
docker cp 容器id:容器内路径 主机目的路径
测试一下
先进入docker中 docker ps
找到运行中的centos
并用命令进入docker容器内部 docker exec -it 容器id /bin/bash
或者 docker attach 容器id
创建一个文件touch test.java
。创建完毕用ls命令查看当前docker centos里的文件,可以看到已经创建成功了
那么下一步就是把他搬到外面的centos里
开始拷贝
从默认路径下的/test.java 拷贝到外面linux的/software路径下
docker cp 1746bd095f04:/test.java /software
运行,拷贝成功,香香!
命令关系图
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 # 截取容器停止时的退出状态值
6.实操
部署Nginx
先去dockerHub找镜像,再拉取镜像
docker pull nginx
查看拉取出来的镜像
docker images
已经拉取成功了
运行测试
~ docker run -d --name nginx00 -p 3344:80 nginx
为什么要-p,因为要打通Linux和docker之间的端口号才能访问,并且在docker内部nginx也是有自己的端口号的,
这里3344是Linux的端口号,80是docker里nginx的端口号,相当于套娃了
如果你想访问容器内的docker就要经历以下步骤
运行,返回一串id
查看一下正在运行的docker镜像服务
正常运行
docker ps
公网访问成功
思考问题
我们每次改动nginx配置文件,都需要进入容器内部?十分的麻烦,要是可以在容器外部提供一个映射路径,达到在容器修改文件名,容器内部就可以自动修改?→ 数据卷!
部署Tomcat
先去dockerHub找镜像,再拉取镜像
docker pull nginx
查看拉取出来的镜像
docker images
已经拉取成功了
运行测试
docker run -d -p 8080:8080 --name tomcat01 tomcat
Linux中的8080端口,docker下的8080接口,因为Tomcat默认给8080端口
外网访问测一下
因为没有网站,所以没有找到,我们进入这个镜像看一下,就是因为webapp下没有东西才会导致的404
发现问题:1、linux命令少了。 2.没有webapps # 阿里云镜像(阉割版),它为保证最小镜像,将不必要的都剔除了→保证最小可运行环境!
思考问题:我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,webapps,我们在外部放置项目,就自动同步内部就好了!
可视化操作页面portainer
Docker图形化界面管理工具!提供一个后台面板供我们操作!
运行如下命令即可 打开可视化服务
docker run -d -p 8080:9000 \ --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
到时候访问ip+8088就可以了
用的比较少
7.Docker镜像讲解
联合文件系统
下载镜像的一层一层的pull下来的东西就是联合文件系统,把每一个文件系统里的文件进行分层处理
说人话就是,复用一些大家都通用的东西,在pull镜像的时候,拉取非通用的、差异的部分就可以了。
UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支 持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite several directories into a single virtual filesystem)。Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应 用镜像
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系 统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
为什么会有这种分层
这种分层的概念和Git差不多,每次来的新东西都是最新的版本
所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层该像当
前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7
是文件5的一个更新版
这种情況下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。
这个镜像里面就有6个layer,也就是6层,到时候拉取这个image时,对六层文件进行分析,拉取差异的部分就行
Docker 镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
我们可以操作的只有镜像层上面的容器层是可以操作的,镜像层是没有办法直接来操作的,因为是你拉取的部分,我们只可以对最上面的容器层进行操作
如何提交一个我自己的镜像
commit镜像
docker commit 提交容器成为一个新的副本
命令和git原理类似
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
实战测试
# 1、启动一个默认的tomcat
docker run -d -p 8080:8080 tomcat bash
# 2、发现这个默认的tomcat 是没有webapps应用,官方的镜像默认webapps下面是没有文件的!
docker exec -it 容器id bash
# 3、拷贝文件进去 ,或者做个修改
# 4、将操作过的容器通过commit调教为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己 的一个修改的镜像。
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]
docker commit -a="kuangshen" -m="add webapps app" 容器id tomcat02:1.0
如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们我们使用虚
拟机的快照。
docker exec -it b8b89ac14ce6 bash
做个修改就新建一个文件吧
touch cc.test
注意,提交这个操作不能在Docker中进行,要退回到linux中再操作
docker commit -m="描述信息" -a="作者" 容器id 目标镜像名: [TAG]
docker commit -m="add test" -a="cc's Tomcat" 容器id tomcat:1.0
查看一下本地镜像,已经提交成功了
8.容器数据卷(重要)
是Docker中的一种同步机制,将docker容器内部的某个文件夹与Linux系统中的某个文件夹进行同步绑定
数据如果数据都在容器中,那么我们容器删除,数据就会丢失!
需求:数据可以持久化
MySQL,容器删除了,删库跑路!需求:MySQL数据可以存储在本地!容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!
容器的持久化和同步操作!容器间也是可以数据共享的!
说穿了就是一种同步机制
使用数据卷
方式一 :直接使用命令挂载 -v (v是volume的缩写)
-v, --volume list Bind mount a volume
docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口
docker run -it -v /home/ceshi:/home centos /bin/bash #通过 docker inspect 容器id 查看
先进入容器内部创建一个同步的测试文件夹(docker目录下)
再开一个Linux窗口,创建一个目标同步的文件夹
在Linux,设置一下目标挂载卷路径
docker run -it -v /synTest:/synTest centos /bin/bash
进入docker容器查看一下相关镜像的具体信息
docker inspect 容器id 查看具体容器的信息
创建文件进行测试
实战MySQL部署以及数据同步到Linux
先拉取MySQL
docker pull mysql
可以看到,已经下载好了
官方提示要设置一下密码
https://hub.docker.com/_/mysql
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
$docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
数据挂载设置
后台启动MySQL,端口映射,Linux的3310映射到docker3306,数据挂载到目标位置
注意:数据挂载是可以通过挂载多个的,按顺序-v挂载就可以了,下面这行命令就是同时挂载conf文件和mysql数据到外面Linux的/mySqlDockerSyn目录下
#启动命令顺带设置mysql用户名和密码
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
-- name 容器名字
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /mySqlDockerSyn:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql1 mysql:8.0
此时测试一下连接MySQL,默认是root
此时我们在容器内部新建一个Test数据库,这个时候Linux就默认同步过来了
具名挂载和匿名挂载
所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data 下
具名挂载
写清楚我们想要挂载的位置
具名挂载 ➜ ~ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
匿名挂载
不写具体同步到哪里,只同步到默认的位置,挂载到容器内路径。这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路劲!
# 匿名挂载 -v 容器内路径!
docker run -d -P --name nginx01 -v /etc/nginx nginx
总结
三种挂载: 匿名挂载、具名挂载、指定路径挂载 -v 容器内路径
匿名挂载 -v 卷名:容器内路径
具名挂载 -v /宿主机路径:容器内路径
指定路径挂载 docker volume ls 是查看不到的
改变挂载位置读写权限
通过 -v 容器内路径:
ro rw 改变读写权限 ro readonly 只读 || rw readwrite 可读可写
docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx
ro(read Only) 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
数据卷容器
说白了就是容器与容器之间进行数据同步
命名的容器挂载数据卷!哪个容器被挂载了,哪个容器被同步了,那个被挂载的容器就是父容器
这里提一个极端情况,就是父容器被删除了子容器会怎么样
这个就像u盘的插拔一样,只要是被拷贝出来的,即便容器被删了(u盘拔出了),也不耽误他原来已经备份好的数据
实现容器间的数据同步
docker run(启动容器) --volumes-from 容器名 路径/文件名称
结论:
容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的
9.DockerFile(重要)
dockerFile也是一种容器数据卷
Dockerfile 就是用来构建docker镜像的构建文件!命令脚本!先体验一下!
通过这个脚本可以生成镜像,镜像。
编写一个DockerFile
# 创建一个dockerfile文件,名字可以随便 建议Dockerfile
# 文件中的内容 指令(大写) 参数
FROM centos #以centos为基础
VOLUME ["volume01","volume02"] #创建两个容器
CMD echo "----end----" # 控制台输出end
CMD /bin/bash #以命令行进行输入
#这里的每个命令,就是镜像的一层!
创建一个dockerfile文件,名字可以随便 建议Dockerfile 文件中的内容 指令(大写) 参数
docker build -f /文件地址 -t 自定义的dockerFile名称 .
我们本身已经在dockerFile目录下,向着目标位置进行build生成我们自定义的image
docker build -f dockerFile -t centosbycc:1.0 .
构建成功
看一下可以支配的镜像
Docker File基础
基础知识:
- 1、每个保留关键字(指令)都是必须是大写字母
- 2、执行从上到下顺序
- 3、# 表示注释
- 4、每一个指令都会创建提交一个新的镜像曾,并提交!
dockerFile build完run起来就有这些东西
Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!
Docker镜像逐渐成企业交付的标准,必须要掌握!
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行产品。
Docker容器:容器就是镜像运行起来提供服务。
# DockerFile常用指令
FROM # 基础镜像,一切从这里开始构建
MAINTAINER # 镜像是谁写的, 姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 保留端口配置
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承 DockerFile 这个时候就会运行ONBUILD的指令,触发指 令。
COPY # 类似ADD,将我们文件拷贝到镜像中 ENV # 构建的时候设置环境变量!
手写一个DockerFile并运行
创建一个dockerFile文件
docker build -f dockerFileCentos -t mycentos:1.0 .
vim myDockerFIle/dockerFileCentos
== 提一个知识点,就是docker的centos里面,是极简版的,没有命令,想要用命令就得自己yum拉取命令,例如之前的/bin/bash 就是带着命令进行操作==
dockerFile内容
FROM centos:7 # 基础镜像,一般其他的镜像的开头是FROM scarth,代表一个普通开始,:7代表下载centos7,下载8的话就容易无法联网,第一行是不可以写注释的!
MAINTAINER cc<123456@qq.com> # 标注制作人名称和联系邮箱
ENV MYPATH /usr/local # 设置一个叫MYPATH的环境路径
WORKDIR $MYPATH # 将MYPATH路径设置为镜像的工作路径
RUN yum -y install vim # yum一个vim编辑器
RUN yum -y install net-tools # yum ip等等命令
EXPOSE 80 # 对外暴露80端口
CMD echo $MYPATH # 输出工作路径
CMD echo "-----end----" # 输出结束
CMD /bin/bash
通过这个文件构建镜像
docker build -f 文件路径 -t 镜像名:[tag] .
在dockerFile目录下运行
docker build -f dockerFileCentos -t mycentos:1.0 .
遇到个坑Error response from daemon: dockerfile parse error line 1: FROM requires either one or three arguments
问题来自于FROM 基础镜像 的第一个注释,会被认为是评论!
我们把第一行注释删掉
这里注释只做演示使用,实际跑起来强烈建议删掉避免不必要的麻烦
构建成功。太长了,没截完
查看一下镜像
docker images
构建好了就可以push到dockerHub之类的,但这就都是后话了
CMD 和 ENTRYPOINT区别
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替 代。
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
10.Tomcat部署实战
准备两个tar安装文件,还有一个DockerFile
编写DockerFile
FROM centos:7
MAINTAINER cc<123456@qq.com>
COPY README /usr/local/README
ADD apache-tomcat-9.0.63.tar.gz /usr/local/
ADD jdk-11.0.13_linux-x64_bin.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local #定义一个MYPATH的路径,以便后面调用
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk-11.0.13_linux-x64_bin #设置环境变量
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.63
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib #设置环境变量 分隔符是:
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.35/bin/startup.sh && tail -F /usr/local/apache- tomcat-9.0.35/logs/catalina.out # 设置默认命令
构建镜像,最后那个点是当前路径下进行构建。
docker build -f tomcatCc -t tomcatcc:1.0 .
看一下docker镜像
docker images
跑起来!
-v是一些运行参数
docker run -d -p 8080:8080 --name tomcatcc -v
/bin/bash是引入命令
docker run -it b69b758cad01 /bin/bash
运行结果(偷来的),可以看到都编排成功了
[root@iZ1608aqb7ntn9Z 20210806]# vim DockerFile2
# -----------写入文件--------------
FROM centos
COPY ymx /opt/Docker/20210806/ymx
ADD jdk8.tar.gz /usr/local
ADD tomcat.tar.gz /usr/local
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_141
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
EXPOSE 8080
# -----------写入文件完成--------------
[root@iZ1608aqb7ntn9Z 20210806]# ls
Dockerfile DockerFile2 ymx
[root@iZ1608aqb7ntn9Z 20210806]# cp /tmp/jdk8.tar.gz jdk8.tar.gz
[root@iZ1608aqb7ntn9Z 20210806]# cp /tmp/tomcat.tar.gz tomcat.tar.gz
[root@iZ1608aqb7ntn9Z 20210806]# ls
Dockerfile DockerFile2 jdk8.tar.gz tomcat.tar.gz ymx
[root@iZ1608aqb7ntn9Z 20210806]# docker build -f ./DockerFile2 -t mytomcat9 .
Sending build context to Docker daemon 197MB
Step 1/11 : FROM centos
......
Successfully built 86a9a8dd939a
Successfully tagged mytomcat9:latest
[root@iZ1608aqb7ntn9Z 20210806]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat9 latest 86a9a8dd939a 26 seconds ago 667MB
......
[root@iZ1608aqb7ntn9Z 20210806]# docker run -it mytomcat9 /bin/bash
[root@ed5fd71834e2 local]# ls
apache-tomcat-9.0.44 bin etc games include jdk1.8.0_141 lib lib64 libexec sbin share src
[root@ed5fd71834e2 local]# java -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)
Push到远程服务器(DockerHub 阿里云)
DockerHub的Push方法
必须注册账号,不注册不行
https://hub.docker.com/
docker login -u 账户 # 回车之后会显示输入密码
password:密码
提交镜像
docker push 镜像名:版本号
这里我们选择第二种
先改tag版本号
docker tag 容器id 用户名/tomcatcc:2.0
再进行push
docker push 用户名/tomcatcc:2.0
push成功
阿里云的Push方法
看官网 很详细https://cr.console.aliyun.com/repository/
$ sudo docker login --username=zchengx registry.cn-shenzhen.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/dsadxzc/cheng:[镜像 版本号]
# 修改id 和 版本 sudo docker tag a5ef1f32aaae registry.cn-shenzhen.aliyuncs.com/dsadxzc/cheng:1.0 # 修改版本
$ sudo docker push registry.cn-shenzhen.aliyuncs.com/dsadxzc/cheng:[镜像版本号]
总结Docker流程
11.Docker网络
理解Docker0
查看一下本机的ip
ip addr
跑一个Tomcat镜像看一下它里面的ip
docker run tomcatId
启动之后,在回到Linux里查看ip
可以发现
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
=======================docker网卡以及docker分配的地址===========================
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3e:0b:db:58 brd ff:ff:ff:ff:ff:ff
inet 172.23.22.131/20 brd 172.23.31.255 scope global dynamic eth0
valid_lft 307272014sec preferred_lft 307272014sec
inet6 fe80::216:3eff:fe0b:db58/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:9b:b8:a2:d4 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
inet6 fe80::42:9bff:feb8:a2d4/64 scope link
valid_lft forever preferred_lft forever
29: veth666f0e9@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 02:87:48:4a:b2:b1 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::87:48ff:fe4a:b2b1/64 scope link
valid_lft forever preferred_lft forever
我们再次进入容器内部,查看一下容器内的地址
可以看到,docker内部也是会有地址的
那么容器与Linux通信的话是否可以ping通?
答案是可以的
容器与容器之间都是Docker内部随便连接,随便ping都能通,但是这个ping不是真ping,是先ping到linux的路由上,再经路由表转发到目标的容器上
结论:tomcat01和tomcat02公用一个路由器,docker0。
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用 ip
那docker和linux,镜像与镜像连接是怎么做到的呢
就是veth-pair技术
veth-pair技术
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要按照了docker, 就会有一个docker0桥接模式,使用的技术是veth-pair技术!
Linux网卡科普
Docker中所有网络接口都是虚拟的,虚拟的转发效率高(内网传递文件,速度和你带宽一致)
只要容器删除,对应的网桥一对就没了!
思考一个场景:我们编写了一个微服务,database url=ip: 项目不重启,数据ip换了,我们希望可
以处理这个问题,可以通过名字来进行访问容器?类似cloud的Feign通过名字调用
容器互联–Link
先测试一下两个镜像之间用容器名字来ping看看是否能成功
docker exec -it Tomcat01 ping Tomcat02
怎么解决呢?只能用–Link来进行指定的名字和名字的连接
运行一个Tomcat03来指定和Tomcat02来连接
docker run -d -P --name tomcat03 --link tomcat02 tomcat
这样是可以ping通的
但是这种玩法有坑,反向ping有概率ping不通
为什么?
因为反向ping没有绑定目标的容器
容器互联自定义网络(常用)
查看一下docker网络
因为docker0,默认情况下不能通过容器名进行访问。需要通过–link进行设置连接。这样的操作比较麻烦,更推荐的方式是自定义网络,容器都使用该自定义网络,就可以实现通过容器名来互相访问了。
下面查看network的相关命令
docker network --help
注意那个inspect的选项,我们借助这个选项来查看一下网桥bridge
docker network inspect bridge
网桥中的详细信息
以上都是docker给你创建的,那么这个时候我们自己创建一个自定义的网络
查看 network create命令的相关参数
docker network help
下面自定义一个网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
具体参数说明:
--driver bridge #指定bridge驱动程序来管理网络
--subnet 192.168.0.0/16 #指定网段的CIDR格式的子网(规定子网号)
--gateway 192.168.0.1 #指定主子网的IPv4或IPv6网关
最后挂上自己自定义的名字
创建成功
此时再看看网络信息:docker network inspect 自定义的网桥名
docker network inspect mynet
可以看到我们自定义的网络ip已经上来了
用自定义网络跑容器
用自定义的网络启动两个tomcat,再查看一下网络状态
[root@iZ8vb4qrjoahmfuzp7tlbhZ ~]# docker run -d -P --name tomcat-net-01 --net mynet tomcat
d77f23b808889613e2e4e9c6f12b109f78316ad1909a2d9a17780bbdfd806592
[root@iZ8vb4qrjoahmfuzp7tlbhZ ~]# docker run -d -P --name tomcat-net-02 --net mynet tomcat
75c10009eb39f40922cf16c9d9087562561f85e5925819b4d6128bc3922d91d2
[root@iZ8vb4qrjoahmfuzp7tlbhZ ~]# docker network inspect mynet
ping测试一下,正向连接和反向连接都试试,都是可以连通的
可以发现,在我们的自定义网络下,容器之间既可以通过容器名也可以通过ip地址进行网络通信。 我们自定义的网络默认已经帮我们维护了容器间的网络通信问题,这是实现网络互联的推荐方式。
Docker网络之间的互联
两个不同的网桥下,想这么连接,是不可以的,连不上
没有设置的情况下,不同网络间的容器是无法进行网络连接的。如图,两个不同的网络docker0和自定义网络mynet的网络模型图:
在默认网络bridge下启动容器tomcat-01,尝试连接mynet网络下的tomcat-net-01容器。
可以看到是无法网络连接的。不同Docker网络之间的容器需要连接的话需要把作为调用方的容器注册一个ip到被调用方所在的网络上。需要使用
docker connect命令
下面设置容器tomcat-01连接到mynet网络上。并查看mynet的网络详情,可以看到给容器tomcat-01分配了一个ip地址。
docker network connect 定定义的网桥号 目标容器名称
docker network connect mynet tomcat-01
设置完成后我们就可以实现不同网络之间的容器互联了。
12.实战
Redis集群部署
集群Redis架构图
一旦主机挂掉了,那么从机就变成主机顶上去
为Redis专门创建一个网卡
docker network create redis --subnet 172.38.0.0/16
通过脚本创建六个redis配置
这里用了一个for循环来实现六个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
粘贴完毕回车就可以运行
创建完配置文件就要开始运行
通过脚本运行六个redis
下面启动6个Redis容器,设置对应的容器数据卷挂载
#第1个Redis容器
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
#第2个Redis容器
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
#第3个Redis容器
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
#第4个Redis容器
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
#第5个Redis容器
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
#第6个Redis容器
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
或者用脚本一次性启动6个也可以
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
启动完成
此时进入redis1容器设置一下创建集群
由于redis内部本身并没有bash命令所以要以sh命令运行
docker exec -it redis-1 /bin/sh #redis默认没有bash
设置负载均衡
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
redis-cli -c
查看节点信息cluster nodes
,可以清楚的看到Redis节点的主从关系。
因为我们是主从的架构,所以我们停掉一个主机,来看看从机能不能顶上来
停掉三号机
稍等一下redis完成选举机制,推选出最新的主机
再次进入redis,可以看到,查询之前的信息也是可以查到的,实现了高可用的目的
分布式SpringBoot项目打包镜像
如果要打包SpringBoot,那我先得有一个SpringBoot项目吧,新建一个项目然后写一个Controller层
先在本地测一下,没毛病,好用
mvn package打包起来,同级目录下创建Dockerfile
Dockerfile内容
FROM java:8 #以java8为基础版本
COPY *.jar /app.jar # 从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
CMD ["--------server.port:8080---------"] # 输出
EXPOSE 8080 # 设置端口号
ENTRYPOINT ["java","-jar","app.jar"] # 自动运行java -jar jar包的命令
把jar包和Dockerfile上传到服务器中,注意创建的时候,名字最好是Dockerfile,不要其他的容易构建的时候报错
直接构建!
查看镜像,跑起来就好了,最后测试
因为80端口我有个项目被占用了,这里就改别的端口号:容器映射来进行访问(后台运行)
docker run -d -p 12138:8080 ccdocker
各位江湖再见啦~