从docker安装到docker容器、docker镜像、docker网络、docker-compose、dockers-swarm、docker-stack等
整理自:bilibili 狂神说
传统应用
缺点1:
一款产品:开发-上线 两套环境! 应用环境,应用配置很麻烦
开发 – 运维。问题,我电脑上可以运行!版本的更新,导致服务不可用了!对于运维人员来说,考验就比较大。
现在情况:开发即运维
缺点2:
环境配置十分麻烦,每一个机器都要部署环境(redis集群、Es集群、Hadoop集群…),费时又费力
发布一个项目:jar+ 环境(redis + mysql + jdk + es等),项目不能带上环境进行打包,配置很麻烦,jar可以跨平台,环境是不能跨平台。如window跨到linux
缺点3:
传统:开发做好jar,剩下运维来做
现在:开发打包部署上线,一套流程做完!
java – apk – 发布(应用商店) — 张三使用apk – 安装即可用!
java – jar (环境) – 打包带上环境 (镜像) – (docker仓库 :商店) – 下载我们发布的镜像 – 直接运行使用
docker的出现:
Dokcer给以上的问题,提出了解决方案。
Docker思想:来源于多集装箱,每个箱子互相隔离
jre – 多个应用(端口错误、配置错误) – 原来环境都是交叉的(用的同一套环境)
vm : linux centos 原生镜像(小型电脑) ,隔离,需要开启多个虚拟机;启动几分钟
缺点:1.资源占用十分多 2.冗余步骤多 3.启动很慢
docker : 隔离,镜像(最核心的环境(4M大小) + jdk + mysql)十分轻巧,运行镜像就可以。启动,秒级别
- 传统虚拟机,虚拟出一套硬件,运行一个完整的操作系统,然后在这个系统上安装和运行文件
- 容器内的应用直接运行在宿主机内核,容器没有自己的内核,也不会虚拟出自己的硬件,轻便
- 每个容器之间是相互隔离,容器内都有一个属于自己的文件系统,互不影响
1、更快速的交付和部署
传统:一堆帮助文档、安装程序
Docker:打包镜像发布测试、一键运行
2、更便捷的升级和扩容
使用了Docker之后,我们部署应用就和搭积木一样 轻松
项目打包为一个镜像,进行扩展。如A服务器出问题了,在B服务器一键运行镜像即可
3、更简单的系统运维
在容器化之后,我们的开发,测试环境都是高度一致的。不出出现本地可以用,线上环境不能用
4、更高效的计算与资源利用(最好的地方)
Docker是内核级别的虚拟化,可以在一个物理机上运行很多个容器实例。服务器性能可以被压榨到极致。
docker镜像就好比一个模板,通过这个模板来创建容器对象
如tomcat镜像 ==>run ==> tomcat01容器(容器提供服务,最终服务运行就是在容器中);
Docker利用容器技术,独立运行一个或一组应用,通过镜像来创建的。
启动、停止、删除等基本命令
目前就是可以把一个容器理解为一个建议的linux系统
仓库存放镜像的地方
公有仓库:
DockerHub (默认国外的)
阿里云、华为…(配置镜像加速!)
私有仓库:搭建自己的私有仓库
# 准备工作
yum -y install gcc
yum -y install gcc-c++
# 1、卸载旧的docker文件
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 2、需要的安装包
yum install -y yum-utils
# 3、设置中央仓库
# 这里是国外的,非常慢
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 这里是国内的,比较快 - 阿⾥云
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 4、安装docker相关的内容,最新的:
#更新yum软件包索引
yum makecache fast
# 5、docker-ce 社区版本(一般使用),docker-ee 企业版;如报错看下面解决方式
yum install -y docker-ce docker-ce-cli containerd.io
# 6、启动docker
systemctl start docker # 第一步:启动docker服务端
docker version # 第二步:启动docker服务端后,查看docker版本。不然只能看到docker-client的版本
# 7、运行hello-world
docker run hello-world
# 8、查看下载的hello-world镜像:(每个服务打包成镜像进行发布)
docker images
#了解:卸载docker
yum remove docker-ce docker-ce-cli containerd.io # 卸载安装的docker软件
rm -rf /var/lib/docker #删除docker在系统的数据文件,docker默认的工作路径
# 9、开机启动
sudo systemctl enable docker
备注:如低5步报错则修改下面:
1.登录阿里云,找到【容器镜像服务】
2.找到镜像加速地址(每个人地址不一样):
3.在系统中配置docker加速器,如上图代码
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://dk3u1mig.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
docker到底是怎么工作的?
docker是一个client-server结构的系统,docker的守护进程运行在宿主机上。通过socket与客户端访问!
docker server接受client指令,就会执行容器命令
1.docker有比VM更少的抽象层。
2.docker利用的是宿主机的内核,VM需要GuestOS。
所以:新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统内核,避免引导。虚拟机是加载的Guest OS,分钟级别的启动。而docker是利用宿主机的操作系统,省略了这个复杂过程,是秒级别启动!
3.docker与vm对比
docker version # 显示docker版本信息
docker info #显示docker的系统信息,包括镜像和容器
docker 命令 --help # 帮助命令;如docker images --help
帮助文档地址:docker官方帮助文档
查看所有本地主机上的镜像
docker images # 列出所有镜像
# 可选项
-a, --all # 列出所有镜像
-q, --quiet # 只显示镜像的id
搜索远程镜像
docker search mysql
# 可选项
-f 过滤 # --filter=STARS=3000
例子:docker search mysql --filter=STARS=3000
docker search mysql -f=STARS=3000
远程拉取镜像到本地
docker pull mysql
或
docker pull mysql[:tag] # tag版本,一般都会加上版本 (通过分层下载,联合文件系统)
# 两个命令等价
docker pull mysql = docker pull mysql:5.7
删除镜像
docker rmi -f 镜像名/镜像ID # -f 强制,多个删除用空格区分
docker rmi -f $(docker images -qa) # 删除所有本地镜像
说明:有了镜像才能创建容器,以下载一个centos镜像来测试学习
docker pull centos
新建容器并启动
docker run [可选参数] image
#参数说明
--name="name" 容器名字,用来区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口 # ip是主机ip吗?
-p 主机端口:容器端口(常用)
-p 容器端口
容器端口
-P 随机指定端口
# 测试:启动并进入容器
[root@localhost ~]# docker run -it centos /bin/bash
[root@1e973315dad7 /]# # 启动已经进入了容器,是一个最初版的centos
[root@1e973315dad7 /]# exit; # 停止并退出容器
查看所有在运行的容器
docker ps # 正在运行的
docker ps -a # 曾经运行的+正在运行的容器
docker ps -n=? # 最近创建的容器,显示数量-n。
docker ps -q # 只显示容器的id
#eg: docker ps -a -n=2 # 显示最近的两个容器
进入容器后退出容器
exit # 停止并退出容器
ctrl+P+Q # 容器不停止且退出
删除容器
docker rm 容器id # 移除单个,如果要强制删除需要加参数:-f
docker rm -f $(docker ps -qa) # 删除所有容器
docker ps -a -q | xargs docker rm # 删除所有的容器
docker start 容器ID #启动容器
docker restart 容器ID #重启容器
docker stop 容器ID #关闭容器
docker kill 容器ID #强制关闭容器
docker run
# 命令 docker run -d 镜像名
docker run -d centos
#存在问题:docker ps时发现centos停止了
#常见的坑:docker容器后台运行,必须要有一个前台进程,如果docker发现没有cli,那么后台应用就会自动停止
#启动nginx,容器启动后,发现自己没有提供服务,就会立即停止。
docker logs
docker logs -f -t --tail n 容器ID # n日志条数,t 时间戳;f 规范显示format
# 自己写一段shell脚本
"while true;do echo biebiebie;sleep 1;done"
docker run -d centos /bin/sh -c "while true;do echo biebie;sleep 1;done"
docker top 容器ID
docker inspect 容器ID
# 方式一:docker exec
docker exec -it 容器ID /bin/bash # /bin/bash:通过哪个命令行进入容器,还有/bin/sh
# 方式二:docker attach
docker attach 容器ID
正在运行的代码.....
#docker exec #开启新的终端进入正在运行的容器,可以操作命令(常用)
#docker attach #进入容器正在执行的终端,不会启动新的终端
docker cp 容器ID:容器内路径 目的主机路径
挂在的方式
#1.启动docker服务,并搜索镜像;建议先看hub.docker.com上进行搜索
docker search nginx
#2.远程下载镜像
docker pull nginx:[版本号]
#3.启动nginx
docker run -d --name nginx01 -p 3344:80 nginx
#4.测试是否启动成功:成功
curl localhost:3344
#安装curl包
#1.下载
wget --no-check-certificate https://curl.haxx.se/download/curl-7.80.0.tar.gz
#2.解压
tar zxvf curl-7.80.0.tar.gz
#3.执行配置文件
cd curl-7.80.0
./configure
#4.make编译
make
# 进入容器查看容器ip:cat /etc/hosts
# 外部查看:docker inspect 容器ID/名称
思考:我们每次改动nginx配置文件,都需要进入容器内部,很麻烦,可以通过容器外部修改直接映射到内部文件吗? -v(数据卷技术)
# 官网使用
docker run -it --rm tomcat:9.0 # --rm:容器运行停止后即删除,一般用于测试
# 下载启动
docker pull tomcat
# 启动运行
docker run -d -p 3355:8080 --name tomcat01 tomcat:[TAG]
#测试,启动成功
#进入容器
docker exec -it tomcat01 /bin/bash
# 发现问题:1.linux命令少了很多 2.在tomcat的webapps里面没内容
# 原因:阿里云的镜像的原因:阿里云镜像默认是最小镜像,所有不必要的内容都会剔除
# es 暴露的端口很多
# es 十分耗内存
# es 的数据一般需要存放到安全目录! 即挂载
# 1.下载镜像与启动:
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#其中:--net somenetwork是docker的网络配置
# 2.启动完之后,linux卡死了
docker stats # 查看docker CPU的状态
# 3.测试es是否启动成功
docker ps
# 4. 赶紧关闭,增加内存的限制。修改es的配置文件
-e 环境修改
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
docker ps # 查看docker进程
思考:网络如何联通?
什么是portainer?
dokcer图像化界面管理工具。提供一个后台面板供我们操作
# 1.拉取镜像安装并启动
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
# 2.测试是否启动成功
在宿主机上执行:curl localhost:8088
# 3.通过浏览器访问:如下图
宿主机ip:8088 -> 192.168.229.131:8088
# 4.一般连接选择本地,如下图
# 5.进入之后的面板
学完镜像才算入门docker
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件。
它包含运行某个软件所需要的所有内容:包括代码、运行时、库、环境变量和配置文件。
所有的应用,直接打包成docker镜像,就可以直接跑运行了。方面扩展和部署
如何得到镜像:
- 从远程仓库下载
- 朋友拷贝
- 自己制作一个镜像,Dockerfile
UnionFS(联合文件系统) :
UnionFS(联合文件系统):UnionFS文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同事可以将不同的目录挂在到同一个虚拟文件系统下。UnionFS是docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像)可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
联合文件系统类似于git的版本提交
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等标准目录和文件。footfs就是各种不同的操作系统发行版,比如ubuntu,Centos等
思考:平常我们安装虚拟机centos都是好几个G,为什么Docker这里才200M?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了。因为底层直接用Host和kernel,自己只需要听过rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。
分层的镜像
在下载镜像时,观察下载时输出的日志,可以看到是一层一层的在下载!如图:
思考:为什么docker镜像要采用这种分层的结构呢?
答:最大的好处就是资源共享了! 比如有多个降序都从相同的base镜像构建而来,那么宿主机啊只需要在磁盘上保留一份base镜像,同事内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像是每一次都可以被共享的。
思考:为什么docker的继承只需要加载一次基础镜像而java中基础需要每次加载基类?
答:java中的继承是有状态的,需要记录每个基类的数据。docker继承是无状态的,所以只加载存储一次即可
查看镜像分层的方式可以通过docker image inspect命令
理解:所有的dokcer镜像都起始于一个基础镜像,当进行修改或增加内容时,就会在当前镜像层之上,创建新的镜像层。
例子:假如基于Ubuntu Linux 16.04创建一个新的镜像,这就新镜像的第一层;如果在该进行中添加Python包,就会在基础镜像层之上创建第二个镜像层;如继续添加一个安全补丁,那么就会创建第三个镜像层。
如下图:
在添加额外的镜像层的同时,镜像始终保持当前所有镜像的并集组合。如下如每层镜像3个文件,打包镜像时会有6个文件,分别来自于不同的镜像层。
如下图:
下图中展示了稍微复制的三层镜像,在外部看来整个镜像只有6个文件,这是因为文件7是文件5的更新版
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件,这样就是的文件的更新版本作为一个镜像层添加到镜像中。
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都是基Linux中对应的文件系统或者快设备技术,并且每种存储引擎都有自己的特点。
Docker在Windows上仅支持windowsFilter这一种存储引擎,并且该引擎基于NTFS文件系统之上实现了分层和CoW[1]。
下图展示了与文件系统相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图
特点
Docker现有pull的镜像都是只读的,当容器启动时,一个新的可写层被加载到docker现有镜像层的顶部,这一层就是容器层,容器之下的都是镜像层。
我们对容器的所有操作都是正在新建一个自己的镜像层,容器commit提交就成为一个新的镜像。
命令:docker commit
解释:提交一个容器成为新的镜像副本
# 命令和git命令类似
docker commit -m="提交描述信息" -a="作者" 容器ID 目标镜像名:[TAG]
以tomcat为例子提交新镜像
# 1、启动一个默认的tomcat
# 2、发现这个默认的tomcat是没有webapps应用,是因为镜像纯净的原因。官方的镜像默认webapps文件夹下是没有文件的
# 3、自己拷贝进去了基本文件
# 4、讲文明操作过的容器通过commit提交为一个镜像(提交的镜像会保存在docker本地,与git也类似),我们以后就使用这个新提交的镜像即可
[root@localhost ~]# docker commit -a="bie" -m="add webapps app" 70b6e29900d3 tomcat02:1.1
# 5、如下图
学习方式说明:理解概念,但是一定要实践,最后理论和实践相结合一次搞定这个知识。
docker精髓:容器数据卷、DockerFile、Docker网络原理三项
数据?如果数据都在容器中,那么我们删除容器,数据就会丢失! 需求:数据可用持久化
mysql安装在docker容器中,容器删除 = 删库跑路! 需求:mysql数据可以存储在本地
容器之间可以有一个数据共享的技术! 卷技术,容器挂载(容器内的目录,挂载到宿主机)
总结:容器的持久化和同步操作!容器间也是可以数据共享的!
使用数据卷:
1.volumns挂载
2.mounts挂载
docker run -it -v 主机目录:容器目录
# 1.执行命令进行挂载
docker run -it -v /home/ceshi:/home centos /bin/bash
# 2.测试,在容器home目录下创建test.txt
结果:宿主机目录下 /home/cesh 有test.txt文件
# 3.docker inspect 容器id/容器名
思考:mysql的持久化问题?data目录挂载
会占用两倍存储空间
# 1.远程下载mysql镜像
docker pull mysql:5.7
# 2.启动mysql
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:5.7
# 注意:conf.d文件为空,正常,需要人为配置
# 3.测试:启动成功后用sqlyog或navicat连接
telnet 192.168.229.131 3310 # 允许登录
# 1.匿名挂载
-v 容器内路径!
-P 随机映射端口 -p指定映射端口
docker run -d -P --name nginx01 -v /etc/nginx nginx
#查看所有挂载映射
docker volume ls
如下显示:
DRIVER VOLUME NAME
local 8a5ae8e2f309a8619fdfb873ce561883498cc1a04572899f0e174548137f45fb #匿名挂载,是真实存在的目录
local 9ba4a4c682727d7584f9143788d66491d9bb267c23b659e002b8b9987379c487 #匿名挂载,是真实存在的目录
# 2.具名挂载
docker run -d -P -v juming-nginx:/etc/nginx --name nginx02 nginx
docker volumn ls
如下显示:
DRIVER VOLUME NAME
local 8a5ae8e2f309a8619fdfb873ce561883498cc1a04572899f0e174548137f45fb
local 9ba4a4c682727d7584f9143788d66491d9bb267c23b659e002b8b9987379c487
local juming-nginx # 具名挂载
下图中:inspect时,Name就是挂载名
# 3.几种挂载-v的写法:
匿名写法:
-v /宿主机路径:容器内路径 # 带/绝对路径,没有名字,例子:-v /home/nginx:/etc/nginx
-v 容器内路径 # 例子:-v /etc/nginx
具名写法:
-v 卷名:容器内路径 # 例子:-v juming-nginx:/etc/nginx
# 4.总结
所有docker容器内的卷,没有指定目录的情况下都是在"/var/lib/docker/volumes/xxxxx(卷名)/_data"
docker工作目录:"/var/lib/docke"
# 5.拓展
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx # ro:只读,只能宿主机改变内容,容器内无法改变此目录及数据
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx # rw:可读写,默认情况
Dockerfile就是用来构建docker镜像的文件!实际上就是命令脚本,通过脚本生成镜像
之前有commit构建docker镜像
# 1.编写dokcerfile文件,脚本如下:
FROM centos #基于centos镜像
VOLUME ["volume1","volume2"] # 这里的写法就是匿名挂载,只写了容器内的目录
CMD echo "---------------end----------------"
CMD /bin/bash
# 2.运行脚本
docker build -f /home/docker-test-volume/dockerfile1 -t kuangshen-centos:1.0 .
#-f 脚本路径; -t 打包版本 ;.标示存放位置
# 3.查看镜像是否构建成功
docker images;
# 4.启动自己构建的镜像
docker run -it kuangshen-centos /bin/bash
发现挂载目录如下图:
被挂载的容器:就是数据卷容器
启动3个容器进行测试:
#启动数据卷容器:
docker run -it --name docker01 kuangshen-centos:1.1
#启动第2个容器:
docker run -it --name dokcer02 --volumes-from docker01 kuangshen-centos:1.1
#启动第3个容器:
docker run -it --name dokcer03 --volumes-from docker01 kuangshen-centos:1.1
#启动第4个容器:挂载docker02上
docker run -it --name dokcer04 --volumes-from docker02 kuangshen-centos:1.1
命令:--volumes-from 类似于java的继承
#测试,删除docker01之后,其他容器中的挂载目录还是有数据
#总结:只要有一个容器还在运行,那么数据就不会丢失
使用docker进行mysql数据同步:
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:5.7
docker run -d -p 3311:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumns-from mysql01 mysql:5.7
(测试时:数据挂载成功了。通过ssh链接时,哪台先开启,就可以连接上哪台。调换先后顺序后,发现创建的数据库test成功,没过3分钟,后启动的mysql自动挂了,很奇怪的现象)
小结:
容器之间配置的信息传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但一旦持久化到宿主机,这个时候宿主机的数据是不会删除的。
dockerfile是用来构建docker镜像的文件,是一个命令参数的脚本!
构建步骤:
1、编写一个docker文件
2、docker build构建成为新的镜像
3、docker run运行镜像
4、docker push发布镜像(DockerHub,阿里云镜像仓库)
追问:有本地镜像仓库?
1.每个保留关键字(指令)都必须是大写字母
2.执行顺序从上到下
3.#标示注释
4.每一更的指令都会创建提交一个新的镜像层,并提交
dockerfile是面向开发的,我们以后要发布项目,做镜像就需要编写dockerfile文件,这个文件十分简单。
docker镜像已经成为开发交付的一个趋势,逐步取代jar,war包
步骤:开发,部署,运维,缺一不可
Dockerfile:构建文件,定义了一切的步骤,原代码
DockerImages:通过dockerfile构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供服务器
以前都是我们使用别人的,现在我们知道这些指令后,自己练习写一个镜像
FROM #基础镜像,一切从这里开始构建
MAINTAINER #镜像作者,姓名+日期
RUN #镜像构建的时候需要运行的命令
ADD #添加文件,如步骤:tomcat镜像,添加tomcat的压缩包
WORKDIR #镜像的工作目录
VOLUMES #挂载的目录
EXPOSE #暴露端口
CMD #指定这个容器启动时需要运行的命令,只有最后一个会生效。有覆盖动作
ENTRYPOINT #指定这个容器启动时需要运行的命令,是追加,无覆盖动作
ONBUILD #当构建一个被继承Dockfile这个时候就会运行ONBUILD命令
COPY #类似ADD,将我们文件拷贝到镜像中
ENV #构建的时候设置环境变量
DockerHub中99%的镜像都是从这个基础镜像构建而来的(FROM scratch)
在原有的centos上,添加vim包和ipconfig包
# 1.编写自己的dockerfile文件
FROM centos # FROM cenos1
MAINTAINER biejiahao<729941382@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
#2.通过这个文件构建镜像
# 命令:docker build -f dockerfile文件路径 -t 镜像名:[TAG] .
本地测试时,这里有问题:
需要将原始centos upstream后发布新版的cenos1,然后再进行build操作
地址:https://blog.csdn.net/weixin_43252521/article/details/124409151
构建成功输出的信息:
Successfully built bf40fedf541b
Successfully tagged mycentos:0.1
# 3.测试运行
docker run -it mycentos:0.1 /bin/bash
vim test.java # 成功
ifconfig # 成功
# 4.查看镜像构建历史
docker history 镜像id
CMD #指定这个容器启动时需要运行的命令,只有最后一个会生效。有覆盖动作
ENTRYPOINT #指定这个容器启动时需要运行的命令,是追加,无覆盖动作
#1 编写dockerfile-cmd的dockerfile文件
FROM centos
CMD ["ls","-a"]
#2 build成为新镜像
docker build -f dockerfile-cmd -t centos-cmd:1.0 .
#3 测试启动centos-cmd:1.0镜像
docker run centos-cmd:1.0 # 成功
#4.测试加参数,本意想表达 ls -al命令
docker run centos-cmd:1.0 -l # 控制台报错
#1 编写dockerfile-entrypoint的dockerfile文件
FROM centos
ENTRYPOINT ["ls","-a"]
#2 build成为新镜像
docker build -f dockerfile-entrypoint -t centos-entrypoint:1.0 .
#3 测试启动centos-cmd:1.0镜像
docker run centos-entrypoint:1.0 # 成功
#4.测试加参数,本意想表达 ls -al命令
docker run centos-entrypoint:1.0 -l # 成功
1.准备镜像文件tomcat压缩包,jdk压缩包
2.编写dockerfile文件,官方命名Dockerfile,build时会自动寻找这个文件并执行,就不需要 -f 指定文件了。
FROM cenos1
MAINTAINER biejihao<729941382@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u301-linux-x64.tar.gz /usr/local
ADD apache-tomcat-8.5.81.tar.gz /usr/local
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_301
ENV CLASSPATH $JAVAHOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.81
ENV CATALINA_BASH /usr/local/apache-tomcat-8.5.81
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-8.5.81/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.81/bin/logs/catalina.out
3.构建镜像
#1.进入到dockerfile文件目录
#2.执行构建命令
docker build -t diytomcat:1.0 .
4.启动镜像
docker run -d -p 9090:8080 --name kuangshentomcat -v /home/build/tomcat/test:/usr/local/apache-tomcat-8.5.81/webapps/test -v /home/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-8.5.81/logs diytomcat:1.0
5.访问测试
curl localhost:9090
# 如果访问不到,就是tomcat没有启动成功
# 1.先排除启动命令是否有误 2.再排除dockerfile脚本是否有误(第一次多半是脚本问题)
6.发布项目(由于做了卷挂载,那么直接在宿主机进行发布项目即可)
在宿主机挂载的test目录进行操作:
mkdir WEB-INF
cd WEB-INF
vim web.xml
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_3_1.xsd"
version="3.1">
</web-app>
将index.jsp文件存放到项目test目录下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello World!</h2>
<%
System.out.println("--------------test---------------------");
%>
</body>
</html>
启动新的tomcat容器
结果:通过浏览器可以访问成功,并且后台日志可以记录访问信息
1.需要注册账号:hub.docker.com
2.确定这个账号可以登录即可
docker login -u 账号 -p 密码
3.在服务器上提交自己的镜像
docker push 镜像名:[tag]
1.登录阿里云
2.找到容器镜像服务
3.创建命名空间(是一个和大的项目组)
4.创建容器镜像(创建时,选择本地仓库)
5.浏览阿里云信息
6.退出dockerhub账号
dokcer logout
7.登录阿里云账号
参考第五点做法
理解docker网络,就是理解dokcer0的网络:docker0=路由器 网络请求中转
清空所有的镜像与容器,方便学习docker网络时的理解
# 启动一个tomcat
docker run -d -P --name tomcat01 tomcat
# 查看容器的内部网络地址 ip addr,发现容器启动的时候会得到一个eth0@if262 ip地址是docker分配的
docker exec -it tomcat01 ip addr
# 异常请参考文章:https://blog.csdn.net/User_bie/article/details/125642454
# 思考:linux宿主机能不能ping通容器内部? 答案:可以
> ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.037 ms
.....
1、每启动一个docker容器,docker就会给容器分配一个ip,完美只要安装了docker就会有一个dokcer0网卡
利用的是桥接模式,使用的是evth-pair技术
宿主机再次测试ip addr
2、再次启动一个新的容器,发现又多了一对网卡
# 我们发现这个容器带来网卡,都是一对一对
# evth-pair就是一对虚拟设备接口,都是成对出现,一端连着协议,一端彼此相连
# 正因为有了这个特性,一般用evth-pair充当一个桥梁,专门连接各种虚拟网络设备
# Openstac,docker容器之间的连接,OVS的连接,都是使用的是evth-pair技术
3、测试tomcat01是否可以ping同tomcat02 答:可以
结论:tomcat01与tomcat02是公用一个路由器,dokcer0
所有容器在不指定网络的情况下,都是通过docker0进行路由,docker0会给容器分配一个默认可用的IP。可用ip数为254个
如:17.18.0.1/16 则可以分配 255*255 - 2(0.0.0.0 与255.255.255.255)个ip
如:17.18.0.1/24 则可以分配 255-1(17.18.0.1)=254 个ip
Docker使用的是linux的桥接:
dokcer中所有的网络接口都是虚拟的。虚拟的转发效率高!
场景,编写一个微服务,database url=ip,项目不重启,数据库ip换了,能否根据名称访问容器而不根据ip访问。因为docker容器每次启动ip都是会变化的
探究:docker network inspect
–link后,会在/etc/hosts配置文件中添加一份映射
目前已经不推荐使用docker0,需要自定义网络:docker0不支持 容器名连接访问
查看所有的docker网络
网络模式:
bridge:桥接docker(默认)
none:不配置网络,不建议
host:和宿主机共享网络
container:容器网络连通(用的少,局限性很大,不建议)
测试:
#1.直接启动的命令 --net bridge 这个参数是默认使用的,即代表dokcer0
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0 特点: 默认网络,域名不能访问, --link可以打通进行连接
#2.我们可以自己定义一个网络,以后启动的容器就在自己定义的网络内运行
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mybet
--driver 网络连接方式
--subnet 子网
--gateway 子网网关
#家用所有的路由器都是这个网络配置
#3.查看当前docker网络
docker networkd ls
#成功
f5aae4c0d555 bridge bridge local
66ad3244c031 host host local
c54074b0a393 mybet bridge local
044d666dd3d7 none null local
#4.使用自定义网络启动tomcat
docker run -d -P --name tomcat-net-01 --net mybet tomcat
docker run -d -P --name tomcat-net-02 --net mybet tomcat
#5.再次两个容器进行ping
docker exec -it tomcat-net-01 ping 192.168.0.3 #192.168.0.3为tomcat-net-02的ip
#成功
docker exec -it tomcat-net-01 ping tomcat-net-02
#成功
自定义的网络docker已经帮我们维护好了对应的网络关系,推荐平时使用自定义网络
好处:
mysql/redis:不同的集群使用不同的网络,保证集群是安全和健康的
如mysql集群需要访问不同网段的redis集群
A网络容器需要与B网卡连通,才能访问B网段下的服务
# 测试tomcat01连通mybet网络
docker network connect mybet tomcat01
# 如下图:连通之后,直接会把这个容器加入到这个网络中
# 这种情况再docker中称为一个容器两个ip,比如阿里云服务器,公网ip与私网ip
结论:假设要跨网络操作,需要使用docker network connect进行连通
redis cluster 多主从集群
# 1.创建redis集群网络
docker network create redis --subnet 172.38.0.0/16
# 2.通过脚本创建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
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
#3.创建redis集群
#3.1进入到某个redis # 以3-master为例
docker exex -it 82a74538a215 /bin/sh
#3.2执行创建集群
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
#3.3中途执行yes
# 注意redis-cli操作集群时,登录需要加参数-c,如:redis-cli -c
小结:使用了docker之后,所有的技术使用的更简单
1.架构springboot项目
2.打包应用
3.编写dockerfile
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
4.构建镜像
5.发布运行
docker单机版(一至八点)
Docker Compose轻松高效来管理容器,定义运行多个容器,一键上线。
Compose是Docker官方的开源项目,需要安装。
Dockerfile 文件能让程序再任何地方运行。web服务,redis,mysql,nginx…多个容器
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
Compose:2个重要概念
服务services:容器-应用(web/redis/mysql…)
项目project:一组关联容器。如博客,web项目,mysql等
# 1.国外镜像,下载慢
curl -SL https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
# 国内镜像,下载很快
sudo curl -L https://get.daocloud.io/docker/compose/releases/download/v2.6.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 2.文件授权
sudo chmod +x /usr/local/bin/docker-compose
# 3.是否安装成功
docker-compose --version
卸载:
官网:https://docs.docker.com/compose/gettingstarted/
1.创建应用
#1.创建一个文件夹
cd /home && mkdir composetest && cd composetest
#2.创建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)
#3.创建文件requirements.txt需要导入的包
内容:
flask
redis
2.创建dockerfile
# 创建Dockerfile文件,目录/home/composetest
vim 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"]
3.创建docker-compose.yml文件(定义整个服务,需要的环境。web redis mysql 等),完成的上线服务
# 创建docker-compose.yml文件,目录/home/composetest
vim docker-compose.ym
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"
4.构建和运行compose
#目录下执行:/home/composetest
docker compose up
5.停止compose
cd /home/composetest && docker-compose stop
crl + c
1、创建compose网络
2、执行docker-compose.yml
3、启动服务:
⠿ Network composetest_default Created 0.3s
⠿ Container composetest-redis-1 Created 0.1s
⠿ Container composetest-web-1 Created 0.1s
docker-compose up:执行后,会自动下载镜像并启动
[root@localhost ~]# docker service ls;# 查看所有服务
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
默认的服务名:文件名_服务名 _num
注意:_num:副本数量
#1.查看docker网络
docker network ls;
#2.查看docker-compose默认网络下的应用
docker network inspect 240d9f259d39
#3.如下图,通过compose启动的项目都在同一个网段下,可以通过域名直接访问调用,不用通过ip进行访问
1.docker镜像,run=>容器
2.dockerfile构建镜像,服务打包
3.docker-compse启动项目(编排,多个微服务/环境)
4.精通docker网络
# 可以理解为核心3层
version: '' # 版本
services: #服务
服务1: web
#dokcer容器配置
images
build
network
服务2: redis
#其他配置 网络/卷/全局规则等
volumes:
networks:
configs:
#1.home目录下创建文件夹:
cd /home && mkdir my_wordpress && cd my_wordpress/
#2.编写docker-compose.yml文件
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
wordpress:
image: wordpress:latest
ports:
- 80:80
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
db_data:
# 3.启动
docker-compose up -d
docker-compose up
1.编写微服务项目
2.编写Dockerfile文件,构建镜像
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8099
ENTRYPOINT ["java","-jar","/app.jar"]
3.编写docker-compose.yml文件,编排项目
version: '3.8'
services:
kuangapp:
build:
dockerfile: Dockerfile
image: kuangapp
depends_on:
- redis
ports:
- "8080:8080"
redis:
image: "redis:alpine" # 精简版本
4.丢到服务器
1.创建kaungapp目录:在目录下操作
2.启动
docker-compose up -d
小结:未来项目只要有dokcer-compose文件。按照这个规则,启动编排容器
假设项目要重新部署打包:
docker-compose up --build # 重新构建镜像
工程、服务、容器
项目compose:三层
集群方式的部署、需要购买4台阿里云服务器,2核心4G。swarm暂时买的1核2G
k8s需要2核4G
#1.初始化一个swarm节点 docker-1机器上操作
docker swarm init --advertise-addr 本机ip
#得到上图两个命令:
# 添加一个工作节点:其他docker机器上操作
docker swarm join --token SWMTKN-1-2lp87oe4q6ez6ehnqz3hs9887hjpe4prasxnafa8y0rsu13q8s-1idmuvh3lojmua824wxgw15ev 172.16.0.105:2377
# 获取一个节点的token,manager的token与worker加入的节点token是不一样的
docker swarm join-token manager
# 添加一个管理节点
docker swarm join --token SWMTKN-1-2lp87oe4q6ez6ehnqz3hs9887hjpe4prasxnafa8y0rsu13q8s-6lxrwnpfoazek2qzfjirda7qs 172.16.0.105:2377
docker swarm join-token work
docker node ls;
1与4主节点。2与3从节点
目前是双主双从:假设一个节点挂了,其他节点是否可用
raft协议:保证大多数节点存活才可以用。集群至少大于3台
将docker1停止(宕机),双主双从的情况下,docker4能否可用?答:不可用
重启dokcer1机器后,docker1不是leader了,docker4升级为leader
docker swarm leave #如下
目前1.3.4是主节点:
集群中:至少要保证3个主节点。必须要保证2台主机存活这个集群才可用。
raft协议:保证大多数节点存活,才可以使用,高可用
灰度发布:金丝雀发布
docker service create -p 8888:80 --name my-nginx nginx
1.docker run 容器启动,不具备扩缩容器
2.docker service 服务启动,具备扩容容器,滚动新
dokcer service ls;
docker service update --replicas 3 my-nginx
注意:外网访问不到,需要配置阿里云安全组,开放端口8888
动态扩缩容
服务,集群中任意的节点都可以访问。
服务可以有多个副本动态扩缩容来实现服务高可用
docker service scale my-nginx=5
docker service scale my-nginx=1
swarm
集群的管理和编排,docker可以初始化一个swarm集群,其他节点可以加入。(管理或工作者)
node:
就是一个docker节点,docker节点就组成了一个集群网络
service
任务,可以再管理节点或工作节点来运行,核心!
task:
容器内的命令,细节任务
docker-compose 单机项目部署
dockerstack 集群部署
#单机
docker-compose up -d wordpress.yml
#集群
docker stack deploy wordpress.yml
安全!配置密码,证书!
配置,统一的配置
http://t.zoukankan.com/goloving-p-14988269.html