Docker
Docker 学习
- docker 安装
- docker命令
- 镜像命令
- 容器命令
- 操作命令
- …
- Docker镜像
- 容器数据卷
- DockerFile
- Docker网络原理
- IDEA 整合Docker
- Dcoker Compose
- Docker Swarm
- CI\CD jenkins
docker 概述
docker为什么出现
一款产品:开发–上线 两套环境!应用环境,应用配置!
开发 ---- 运维。 问题:
传统:开发jar包,运维来做
现在:开发打包部署上线,一套流程做完!
java – apk --发布(应用商店)----张三使用apk —安装即可用!
jav – jar(环境) – 打包项目带上环境(镜像) – ( Docker仓库:商店 )----下载我们发布的镜像—直接运行即可!
Docker给以上的问题,提出了解决方案!
Docker 的思想就来自于集装箱!
JRE – 多个应用(端口冲突) — 原来都是交叉的!
隔离:Docker核心思想 !打包装箱! 箱子之间相互隔离
Docker 通过隔离机制 ,可以将服务器利用到极致!
本质:所有的技术都是因为出现了一些问题
Docker 的历史
2010, 几个搞IT的年轻人,在美国成立一家公司dotCloud
做一些 pass 的云计算服务! LXC有关的容器技术!
他们将自己的技术(容器化技术)命名 就是Docker
Docker 刚刚诞生的时候,没有引起行业的注意!dotCloud,就活不下去
开放源代码
Docker 越来越多的人发现了docker的优点!docker 每个月都会更新一个版本
Docker为什么这么火!十分的轻巧
在容器技术出来之前,我们都是使用的虚拟机技术!
虚拟机:在window中安装一个Vmware ,同过这个软件我们可以虚拟出来一台或多台电脑!笨重
虚拟机也是属于虚拟化技术,Docker 容器技术 ,也是一种 虚拟化技术
vm: linux centos 原生镜像(一个电脑!) 隔离,需要开启多个虚拟机! 几个G 几分钟
docker: 隔离 ,镜像(核心的环境 4m+JDK +mysql) 十分的小巧 ,运行镜像就可以
docker 是基于 Go语言开发的!开源项目
·Docker 能干嘛
普通电脑运行机制
容器化技术不是墨迹的一个完整的操作系统
比较 Docker 和虚拟机技术的不同
- 传统虚拟机 ,虚拟出一条硬件,运行一个完整的操作系统 ,然后再这个系统上安装和运行软件
- 容器内的应用直接运行在宿主机上的内容,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了
- 每个容器间是相互隔离,每个容器内都有一个属于自己的文件系统,互不影响
devOps (开发、运维)
应用更快速的交付和部署
传统:一堆帮助文档,安装程序
Docker:打包镜像测试,一键运行
更便捷的升级或扩缩容
使用了Docker之后,我们部署应用就和搭积木·一样
项目打包未一个镜像,扩展 服务器A! 服务器B
更简单的系统运维
在容器化之后,我们的开发,测试环境是高度一致的
更高效的计算资源利用
docker 是内核级别的虚拟化,可以再一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致
Docker的基本组成
镜像(image):
docker镜像就像一个模板,可以通过这个模板来创建容器服务,tomcat镜像===》run ==》tomcat01 容器
通过这个镜像可以创建多个容器 (最终服务运行或者)
容器(contanier):
Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的
启动,停止,删除,基本命令
仓库(repository):
仓库就是存放镜像的地方
仓库分为公有仓库和私有仓库!
Docker Hub(默认是国内的)
阿里云…都有容器服务器(配置镜像加速!)
安装docker
环境准备:
用xshell 理解上服务器(记得设置安全组打开22端口)
安装
帮助文档:
# 1、卸载旧的版本
yum remove docker \
docker-client \
docker-client-lastest \
docker-common \
docker-latest \
docker-latest-logrotate \
docekr-engine
# 2、需要的安装包
yum install -y yum-utils
# 3、设置镜像仓库
yum-config-manager \
--add-repo \
https://download.docker.com/lunix/centos/docker-ce.repo #默认是从国外的!
yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #建议用国内阿里云镜像
# 更新yum软件包索引
yum makecache fast
# 4、安装docker相关的内容 docker-ce 社区办 ee企业版
yum install docker-ce docker-ce-cli containerd.io
# 5、启动docker
systemctl start docker
# 6、测试docker是否启动成功
docker -version
# 7、测试hello-world
docker run hello-world
# 8、查看下下载的hello-world镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 11 months ago 13.3kB
#卸载docker
#1.卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
#2、删除资源
rm -rf /var/lib/docker
# /var/lib/docker docker默认工作路径
配置阿里镜像加速器
1.访问阿里云服务
2.找到镜像加速地址
3、配置使用
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://l1m9m3zg.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
底层原理
Docker是什么工作的?
Docker 是一个Client-Server结构的系统,Docker的守护进行运行在主机上。通过Socket从客户端访问!
DockerServer 接收到 Docker-Client的指令,就会执行这个命令
Docker为什么比VM快?
1、Docker有着比虚拟机更少的抽象层
2、Docker利用的是宿主机的内核,vm需要是 Guest OS
所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统内核,避免引导。虚拟机是加载Guest OS,分钟级别的,而docker 是利用 宿主机的操作系统吗,省略了这个复杂的过程。
Docker的常用命令
帮助命令
docker -version # 显示docker的版本信息
docker info # 显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help # 万能命令
帮助的文档地址
镜像命令
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 11 months ago 13.3kB
#解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
#可选项
-a,--all #列出所有镜像
-q,--quiet #只显示镜像的id
docker search 搜索镜像
[root@iz2ze4axajsdleozcknrk7z ~]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10281 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3801 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 749 [OK]
percona Percona Server is a fork of the MySQL relati… 515 [OK]
#可选项,通过收藏来过滤
--filter=starts=3000 #搜索出来的就是收藏大于300的
docker pull 拉取镜像
#下载镜像 docker pull 镜像[:tag]
[root@iz2ze4axajsdleozcknrk7z ~]# docker pull mysql
Using default tag: latest #如果不写tag,默认就是latest
latest: Pulling from library/mysql
6ec7b7d162b2: Pull complete #分层下载, docker image 的核心 联合文件系统
fedd960d3481: Pull complete
7ab947313861: Pull complete
64f92f19e638: Pull complete
3e80b17bff96: Pull complete
014e976799f9: Pull complete
59ae84fee1b3: Pull complete
ffe10de703ea: Pull complete
657af6d90c83: Pull complete
98bfb480322c: Pull complete
9f2c4202ac29: Pull complete
a369b92bfc99: Pull complete
Digest: sha256:365e891b22abd3336d65baefc475b4a9a1e29a01a7b6b5be04367fcc9f373bb7
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
#等价于
docker pull docker.io/library/mysql:latest
#指定版本下载
[root@iz2ze4axajsdleozcknrk7z ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
6ec7b7d162b2: Already exists
fedd960d3481: Already exists
7ab947313861: Already exists
64f92f19e638: Already exists
3e80b17bff96: Already exists
014e976799f9: Already exists
59ae84fee1b3: Already exists
7d1da2a18e2e: Pull complete
301a28b700b9: Pull complete
979b389fc71f: Pull complete
403f729b1bad: Pull complete
Digest: sha256:d4ca82cee68dce98aa72a1c48b5ef5ce9f1538265831132187871b78e768aed1
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
docker rmi 删除镜像
[root@iz2ze4axajsdleozcknrk7z ~] #docker rmi -f 镜像id #删除指定的镜像
[root@iz2ze4axajsdleozcknrk7z ~] #docker rmi -f 镜像id 镜像id 镜像id #删除多个镜像
[root@iz2ze4axajsdleozcknrk7z ~]# docker rmi -f $(docker images -aq) #删除全部镜像
容器命令
我们有了镜像才可以创建容器,lunix,下载一个centos镜像来测试学习
docker pull centos
新建容器并启动
# docker run [可选参数] image 命令# 参数说明--name="Name" 容器名字 tomcat01 tomcat02 用来区分容器-d 后台方式运行-it 使用交互式方式运行,进入容器查看内容-i : 交互模式运行容器,通常与-t同时使用-t: 为容器重新分配一个伪输入终端, 通常与-i同时使用-p 指定容器的端口 -p ip:主机端口:容器端口 -p 主机端口:容器端口 -p 容器端口-p 随机指定端口#测试,启动并进入容器docker run -it centos /bin/bashls # 查看容器内的centos,基础版本,很多命令不完善bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var#从容器中退出exit
列出所有的运行命令
# docker ps 命令 # 列出当前正在运行的容器-a # 列出当前正在运行的容器+带出历史运行过的容器-n = ? #显示最近创建的容器-q #只显示容器的编号
退出容器
exit # 直接容器停止并退出ctrl+P+Q # 退出但容器不停止
删除容器
docker rm 容器id # 删除指定容器 ,不能删除正在运行的容器 ,强制删除用 rm -fdocker rm -f $(docker ps -aq) # 删除所有容器docker ps -a -q|xargs docker rm # 删除所有容器
启动和停止容器
docker start 容器id #启动容器docker restart 容器id # 重启容器docker stop 容器id # 停止当前正在运行的容器docekr kill 容器id # 强制停止容器
常用的其他命令
后台启动容器
# 命令 docker run -d 镜像名docker run -d centos#问题docker ps ,发现 centos 停止了#常见的坑:docker 容器 使用后台运行,就必须要有一个前台进程,docker 发现没有应用,就会自动停止#nginx,容器启动后,发现自己没有停止服务
查看日志
docker logs -f -t --tail 容器,没有日志#自己编写一段shell脚本#docker run -d centos /bin/sh -c"while true;do echo abc;sleep 1;done"# docker psCONTAINER ID IMAGE 5afee754a6a4 centos #显示日志-tf #显示日志--tail number #显示日志条数# docker logs -tf --tail 10 5afee754a6a4
查看容器中的进程信息ps
# 命令 docker top 容器id[root@iz2ze4axajsdleozcknrk7z ~]# docker top e789eb01915aUID PID PPID C STIME TTY root 20642 20622 0 15:26 ? root 20700 20642 0 15:26 ?
查看镜像的元数据
#命令docker inspect 容器id
进入当前正在运行的容器
# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
#命令
docker exec -it 容器id bashShell
#方式二
docker attach 容器id
#测试
正在执行当前的代码。。。。
#docker exec # 进入容器后开启一个新的终端,可以在里面操作
#docker attach # 进入容器后正在执行的终端,不会启动新的进程
从容器内拷贝文件到主机上
docker cp
#测试
#查看当前主机目录下
[root@iz2ze4axajsdleozcknrk7z home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5450d9097ba7 centos "/bin/bash" 2 minutes ago Up About a minute interesting_wing
#进入docker内部
[root@iz2ze4axajsdleozcknrk7z home]# docker attach 5450d9097ba7
[root@5450d9097ba7 /]# cd /home
[root@5450d9097ba7 home]# ls
# 在容器内新建一个文件
[root@5450d9097ba7 home]# touch test.java
# 退出容器
[root@5450d9097ba7 home]# exit
exit
# 查看已创建容器
[root@iz2ze4axajsdleozcknrk7z home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5450d9097ba7 centos "/bin/bash" 3 minutes ago Exited (0) 7 seconds ago interesting_wing
#讲文件拷贝出来到主机上
[root@iz2ze4axajsdleozcknrk7z home]# docker cp 5450d9097ba7:/home/test.java /home
[root@iz2ze4axajsdleozcknrk7z home]# ls
admin lxx.java test.java
#拷贝是一个手动过程,未来我们使用 -v卷的技术,可以实现,自动同步 /home /home
可视化工具
什么是portainer
Docker 图形化界面管理工具!提供一个后台面板供我们操作
docker run -d -p 8088:9000 \--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
访问测试: 外网:8080
进入后的面板
可视化面板一般不会使用
docker 镜像讲解
镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于环境开发的软件,它包含运行某个软件所需要的所有内容,包括代码、运行时、库、环境变量和配置文件
所有的应用,直接打包docker 镜像,就可以跑起来
如何得到镜像
- 从远程仓库下载
- 朋友拷贝给你
- 自己制作镜像
分层理解
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过docker image inspect命令!
"RootFS": { "Type": "layers", "Layers": [ "sha256:7e718b9c0c8c2e6420fe9c4d1d551088e314fe923dce4b2caf75891d82fb227d", "sha256:89ce1a07a7e4574d724ea605b4877f8a73542cf6abd3c8cbbd2668d911fa5353", "sha256:9eef6e3cc2937e452b2325b227ca28120a70481be25404ed9aad27fa81219fd0", "sha256:c6e23529840f1d7025d61f4e41781d16fff2c0a2639484e9c0a2e516ed98c23a", "sha256:0c895bca4020c183c3f093cf920d29460ac5a25b7e48210d9f0655b1e115b7af", "sha256:fa723b6cb1b660d6c745a09892783a552657b9dba07f52974cb88365281feb19" ] }
理解
所有的Docker(镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示 (这只是一个用于演示的很简单的例子) 。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统.
Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及 ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker在Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW[1].下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
commit 镜像
docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]
#启动一个默认的tomcat#发现这个默认的tomcat是没有webapps 应用,镜像的原因,官方的默认镜像webapps下面是没有文件的#自己拷贝进去基本的文件#将修改过的容器通过commit提价为一个镜像!我们以后就使用修改过的镜像即可。
docker run -d --name=typecho-blog --restart always -e PHP_TZ=Asia/Shanghai -e PHP_MAX_EXECUTION_TIME=600 -p 80:80 -v 80x86/typecho:latest
容器数据卷
docker容器数据卷是什么?
当我们在使用docker容器的时候,会产生一系列的数据文件,这些数据文件在我们关闭docker容器时是会消失的,但是其中产生的部分内容我们是希望能够把它给保存起来另作用途的,Docker将应用与运行环境打包成容器发布,我们希望在运行过程钟产生的部分数据是可以持久化的的,而且容器之间我们希望能够实现数据共享。
通俗地来说,docker容器数据卷可以看成使我们生活中常用的u盘,它存在于一个或多个的容器中,由docker挂载到容器,但不属于联合文件系统,Docker不会在容器删除时删除其挂载的数据卷。
特点:
- 数据卷可以在容器之间共享或重用数据
- 数据卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
总结:容器的持久化和同步操作!容器间也是可以数据共享的
添加数据卷
添加数据卷的方式有两种,第一种是直接通过命令行挂载,第二种是通过dockerFile添加
第一种 命令行挂载
docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名
这个命令会在宿主机和容器内分别建立两个目录,两个目录是对接的,里面的数据可以共享。如果我们不知道数据卷是否挂载成功时,我们可以通过以下方式来检查数据卷的挂载结果。
docker inspect 容器id
我们再挂载的时候还可以给数据卷加上权限,假如我们要宿主机只能读取容器的数据卷内容不能修改,我们可以添加只读权限
docker run -it -v /宿主机绝对路径目录:/容器内目录 :ro 镜像名
第二种 利用dockerFile的形式添加
dockerFile对于docker镜像而言就如同java中某个类的.class文件对应上该类的.java文件。
首先在linux服务器根目录上新建docker文件夹并建立DockerFile文件,使用volume命令(出于可移植可分享的的考虑,用以上 -v /宿主机绝对路径目录 : /容器内目录 的这种方式不能够直接在dockerFile中直接实现,因为宿主机目录是依赖于特定的宿主机的,并不能保证所有的宿主机都存在这样特定的目录)
FROM 镜像名VOLUME ["/生成的目录路径"] -- privileged=trueCMD echo "success build"CMD /bin/bash# 参数解释FROM 来自于一个父类的镜像VOLUME 给镜像添加一个或多个容器卷CMD 控制台执行的命令
相当于命令行: docker run -it -v /宿主机目录路径 : /生成的目录路径
然后我们通过命令行docker build执行我们写好的dockerFile文件(docker build和docker commit两个命令都可以建立docker镜像,docker commit 需要在容器内进行,docker build 不需要)
docker build -f /docker/DockerFile -t 命名空间/镜像名 .参数: -f 指定dockerfile 文件,默认情况下在执行命令的目录下寻找 Dockerfile 文件 -t 指定镜像名称 . 在当前目录下生成镜像
docker build -f /root/Dockerfile -t image/test .
运行我们自己构建的镜像,并进入镜像,查看我们自己生成镜像时创建的文件夹
在宿主机中查看我们在容器卷中创建的文件,和写入的文件内容。
注: 可以使用 ctrl + q + P 退出容器,让容器进入后台运行。退回宿主机中
使用 inspct 命令查看容器信息找到宿主机中相应的容器卷
docker inspect 8c05c7c1eec4
可以看到test.txt已经同步到宿主机对应的挂载目录中
Docker 镜像原理
Docker 镜像加载原理
commit镜像
docker commit 提交容器成为一个新的副本#命令和git原理类似docker commit -m"提交的描述信息" -a"作者” 容器id 目标镜像名:[TAG]
容器数据卷
什么是容器数据卷
docker理念回顾
将应用和环境打包成一个镜像
如果将数据存在容器中,容器删除,数据就会丢失
容器之间可以有一个数据共享的技术!Docker 容器产生的数据同步到本地
目录的挂载,将我们容器内的目录,挂在到linnux上
容器的持久化和同步操作 容器间也是可以共享数据的!
使用数据卷
方式一:直接使用命令挂在 -v
docker run -it -v 主机目录:容器内目录# 测试docker run -it -v /home/ceshi:home centos /bin/bash#启动起来时我们可以通过 docker inspect 容器id
修改本地,容器会自动同步
实战 :安装Mysql
#获取镜像 docker pull mysql:5.7# 运行容器,需要数据挂载! # 安装启动 mysql,需要配置密码的,这是要注意点docker run -d #后台方式启动 -p 3306:3306 #端口映射 -v /home/mysql/conf:/etc/mysql/conf.d #数据卷挂载 配置文件同步 -v /home/mysql/data:var/lib/mysql #data数据同步 -e MYSQL_ROOT_PASSWOR= 123456 #环境配置 设置mysql 密码 --name mysql01 #设置容器名字#启动成功用本地连接
将容器删除 挂载在本地的数据卷依旧没有丢失,这就实现了容器数据化功能
具名挂载 和 匿名挂载
#匿名挂载-v 容器内路径docker run -d -p --name nigux01 -v /etc.nginx #查看所有 volume 的情况docker volume ls#这里发现
结果为这样 这种就是匿名挂载,我们在 -v 只写了容器内的路径,没有写容器外的路径
#具名挂载docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx 95b809564484c8ac87d65c69643e7e67447f1c77ff9a91b93edec7003692e3a9[root@kuangshen home]# docker volume lsDRIVER VOLUME NAMElocal juming-nginx# 通过 -v 卷名:容器内路径# 查看一下这个卷
所有docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx
我们通过具名挂载可以方便的找到我们的一个卷,大多数情况下使用的是具名挂载
# 如果确定是具名挂载还是匿名挂载,还是指定路径挂载-v 容器内路径 #匿名挂载-v 卷名:容器内路径 #具名挂载-v /宿主机路径::容器内路径 #指定路径挂载
拓展:
# 通过 -v 容器内路径:ro rw 改变读写权限 ro readonly 只读rw readwrite 可读可写# 一旦这个设置了容器权限 容器对我们挂载出的内容就有限定了docker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:ro nginxdocker run -d -p --name nginx02 -v juming-nginx:/etc/nginx:rw nginx# ro 只要看到ro就说明这个路径只能通过宿主机操作,容器内部是无法操作的
Dockerfile
初识Dockerfile
dockerfile 就是用来构建docker镜像的构建文件,
通过这个脚本可以生成镜像,镜像是一层一层的,每个命令都是一层
#创建一个dockerfile 文件,文字可以随机,建议DockerFile#文件中的内容 指令(大写) 参数FROM centosVOLUME["volume01","volume02"]CMD echo "---end---"CMD /bin/bash
# 启动自己的容器
这个卷和外部一定有一个同步的目录!
查看一下卷挂载的路径
测试一下刚才的文件是否同步出去了!
这种方式我们未来使用的十分多,因为我们通常会构建自己的镜像!
假设构建镜像时没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!
数据卷容器
多个mysql同步数据
# 启动三个容器,通过我们刚才自己的镜像启动
docker 01 上的数据同步到了docker02 上
# 测试:删除docker01,查看docker02和docker02是否还可以访问到这个文件# 测试依旧可以访问
多个mysql数据共享
#docker run -d -p 3306:33-6 -v /etc/mysql/conf.d -v var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7#docker run -d -p 3306:33-6 -v /etc/mysql/conf.d -v var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql:5.7#这个时候,可以实现多个容器数据同步
结论:
容器之间配置信息的传递,容器数据卷的生命周期一直持续到没有容器使用为止
DockerFile介绍
dockerfile 是用来构建docker镜像的文件!命令参数脚本
构建步骤
1、编写一个dockerfile 文件
2、docker bulid 构建成为一个镜像
3、 docker run 运行镜像
4、docker push 发布镜像
查看官方是怎么做的
很多官方镜像都是基础包,很多功能都没有,我们通常会自己搭建自己的镜像
Dockerfile构建过程
基础知识:
1、每个保留关键字(指令)必须是大写字母
2、 从上到下的顺讯执行
3、#表示注释
4、每一个指令都会创建提交一个新的镜像层,并提交!
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 # 构建的时候设置环境变量
实战测试
Docker Hub 中99% 镜像都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行的构建
创建一个自己的centos
# 1.编写Dockerfile的文件
FROM centos
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 docker文件路径 -t 镜像名:[tag]
我们可以列出本地进行的变更历史
CMD 和 ENTRYPOINT 的区别
#编写dockerfile文件
vim dockerfile-cmd-test
FROM centos
CMD ["1s ","-a"]
#构件镜像
docker build -f dockerfile-cmd-test -t cmdtest .
# run运行,发现我们的1s -a 命令生效
docker run dd8e4401d72f
..
.docker
env
bin
devet
chome
lib
lib64
#想追加一个命令-1 1s -al
[root dockerfile]# docker run dd8e4401d72f -l
docker: Error response from daemon: 0CI runtime create failed: container_linux.go:349: startingcontainer process caused "exec: \"-l\ ": executable file not found in SPATH": unknown.
# cmd的清理下-l 替换了CMD ["1s " , "-a"]命令,-1 不是命令所以报错!
实战:Tomcat镜像
- 准备镜像文件 tomcat压缩包,jdk的压缩包
- 编写Dockerfile文件
# 1.编写dockerfile的文件
FROM centos
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u11-linux-x64.tar.gz /usr/local/ADDapache-tomcat-9.0.22.tar.gz /usr/local/
RUNyum-y install vim
ENV MYPATH/usr/localWORKDIR $MYPATH
ENV JAVA HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarENV CATALINA_HOME/usr/local/apache-tomcat-9.0.22
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.22
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CND /usr/local/apache-tomcat-9.0.22/bin/startup.sh & tail -F /url/local/apache-tomcat-9.0.22/bin/logs/catalina.out
- 构建镜像
docker build -t tomcat
发布自己的镜像
- dockerhub 注册自己的账号
- 确认这个账号可以登录
- 在我们服务器上提交自己的镜像
docker login -u 账号名
- 登录完毕后就可以提交自己的镜像
# docekr push lxx/diytomcat:1.0
# push 镜像如果push不上,增加一个标签
# docker tag 镜像id 版本名
阿里云镜像服务上
1、登录阿里云
2、找到容器镜像服务
3、创建命名空间
4、创建容器镜像
Docker 网络
三个网络
# 问题: docker 是如何处理容器网络访问的
# [root@kuangshen /]# docker run -d -p --name tomcat01 tomcat
#查看容器的内部网络地址 ip addr ,发现容器启动的时候会得到一个eth0@if262 ip地址,docker分配的![root@kuangshen/]# 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
va7id_lft forever preferred_lft forever
261: eth0@if262:<BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state Up group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff 7ink-netnsid o
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
#思考。liunx能不能 ping 通容器
[root@kuangshen /]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2)56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 tt1=64 time=0.067 ms64 bytes from 172.18.0.2: icmp_seq=2 tt1=64 time=0.055 ms
# linux 可以ping通容器内部
原理
1、我们每启动一个docker容器。docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术
再次测试 ip addr
2、 再启动一个容器,发现多了一对网卡!
# 我们发现这个容器带来的网卡,都是一对的
# evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁
# OpenStac,Docker容器之间的连接,OVS的连接,都是使用 evth-pair 技术
3、我们来测试两个容器之间是否能ping通
# 容器和容器之间是可以互相ping通的
结论:tomcat01 和 tomcat02 是公用的一个路由器 ,docker0
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我的容器分配一个默认的可用IP
Docker中的所有的网络接口都是虚拟的。虚拟的转发效率高!(内网传递文件!)
只要容器删除,对应网桥一对就没了!
–link
思考一个场景,我们编写了一个微服务,database url =ip,项目不重启,数据ip换掉了,我们希望可以处理在这个问题,可以通过名字来访问网络、
[root@kuangshen/]# docker exec -it tomcat02 ping tomcat01ping: tomcat01: Name or service not known
#如何可以解决呢?
[root@kuangshen/]# docker exec -it tomcat02 ping tomcat01ping: tomcat01 : Name or service not known
[root@kuangshen /]# docker run -d -p --name tomcat03 --link tomcat02 tomcat5ca72d80ebb048d3560df1400af03130f37ece244be2a54884336aace2106884
[root@kuangshen /]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3)56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 tt1=64 time=0.100 ms64 bytes from tomcat02 (172.18.0.3): icmp_seq=2 tt1=64 time=0.066 ms64 bytes from tomcat02 (172.18.0.3): icmp_seq=3 tt1=64 time=0.067 ms
I
--- tomcat02 ping statistics ---
3 packets transmitted,3 received,0% packet loss, time 1000msrtt min/avg/max/mdev = 0.066/0.077/0.100/0.018 ms
link的原理
其实这个tomcat03 就是在本地配置了tomcat02 的配置
#查看hosts 配置,在这里原理发现!
[root@kuangshen /]# docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 locaThost ip6-1ocalhost ip6-loopback
fe00::0 ip6-loca1net
ff00::0 ip6-mcastprefix
ff02::1 ip6-a71nodes
ff02::2 ip6-a11routers
172.18.0.3tomcat02 312857784cd4
172.18.0.4 5ca72d80ebb0
本质探究:–link就是我们在hosts配置中增加了一个172.18.0.3 tomcat02 312857784cd4
这种方式不建议使用
自定义网络
查看所有的docker网络
网络模式
bridge:桥接
none: 不配置网络
host:和宿主机共享网络
container:容器网络连通!(用的少!局限性很大)
测试
# 我们直接启动的命令 --net bridge ,这个网络就是我们的docker0
docker run -d -p --name tomcat01 tomcat
docker run -d -p --name tomcat01 --net bridge tomcat
# docker0 特点:默认,域名不能访问,--link可以打通连接!
# 可以自己创建一个网络
[root@kuangshen /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
eb21272b3a35ceaba11b4aa5bbff131c3fb09c4790f0852ed4540707438db052
[root@kuangshen /]# docker network ls
NE TWORK ID NAME DRIVER SCOPE
5a008c015cac bridge bridge local
db44649a9bff composetest_default bridge local
ae2b6209c2ab host host local
eb21272b3a35 mynet bridge local
#再次测试ping连接
[root@kuangshen /]# docker exec -it tomcat-net-01 ping 192.168.0.3
PING192.168.0.3 (192.168.0.3)56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 tt7=64 time=0.085 ms
64 bytes from 192.168.0.3: icmp_seq=2 tt1=64 time=0.070 ms
--- 192.168.0.3 ping statistics ---
2 packets transmitted,2 received,0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.070/0.077/0.085/0.011 ms
# 现在不使用--link也可以ping名字了
[root@kuangshen /]# docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3)56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.063 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.073 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=4 tt1=64 time=0.070 ms
好处:
redis-不同的集群使用不同的网络,保证集群是安全和健康的
mysql -不同的集群使用不同的网络,保证集群是安全和健康的
网络连通
# 测试打通 tomcat01 -mynet
# 连通之后就是将 tomcat01 放到了mynet 网络下
# 一个容器两个ip!
# 阿里云服务,公网ip 私网ip
此时可以发现容器成功的加入了mynet网络
# 01连通ok
[root@kuangshen /]# docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-o1 (192.168.0.2)56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.072 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.070 ms
#02是依旧打不通的
[root@kuangshen /]# docker exec -it tomcat02 ping tomcat-net-01ping: tomcat-net-01 : Name or service not known
结论:假设需要跨网络操作别的容器,就需要使用docker network connect 连通。。。
实战:部署Redis集群
# 创建网卡
docker network create redis --subnet 172.38.0.0/16
#通过脚本创建六个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-bus-port 16379
appendonly yes
EOF
done
for port in $(seq 1 6);\
do \
docker rm -f redis-${port};
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 redis-server /etc/redis/redis.conf;
done
# 创建集群
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
# 显示结果
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: 12ccc413ed4e351aceed1d738f4b3abf415be47c 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 98b58f8d0e29f6fe4317a745d79f3ec11a3fda3d 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: dc3f1a2b9da08d94256d3beef69d9f64711815d8 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 2615c949c02207e54664c5f11bd615388f66b043 172.38.0.14:6379
replicates dc3f1a2b9da08d94256d3beef69d9f64711815d8
S: 0d39e27b5f5fdc1353094107df06ccf127f39d5e 172.38.0.15:6379
replicates 12ccc413ed4e351aceed1d738f4b3abf415be47c
S: 64dd8e732978a6cbf68c753ac9dfcaff66599450 172.38.0.16:6379
replicates 98b58f8d0e29f6fe4317a745d79f3ec11a3fda3d
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: 12ccc413ed4e351aceed1d738f4b3abf415be47c 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 2615c949c02207e54664c5f11bd615388f66b043 172.38.0.14:6379
slots: (0 slots) slave
replicates dc3f1a2b9da08d94256d3beef69d9f64711815d8
S: 64dd8e732978a6cbf68c753ac9dfcaff66599450 172.38.0.16:6379
slots: (0 slots) slave
replicates 98b58f8d0e29f6fe4317a745d79f3ec11a3fda3d
S: 0d39e27b5f5fdc1353094107df06ccf127f39d5e 172.38.0.15:6379
slots: (0 slots) slave
replicates 12ccc413ed4e351aceed1d738f4b3abf415be47c
M: dc3f1a2b9da08d94256d3beef69d9f64711815d8 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 98b58f8d0e29f6fe4317a745d79f3ec11a3fda3d 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
docker 搭建redis集群完成