如何构建自己的镜像?如何让别人获取我们的镜像?如何实现容器之间通信?
今天这篇博客就从解决这3个如何开始
No.one
如何构建自己的镜像?
我目前知道的有2种形式。
第一种,如果我们下载了一个官网的镜像,通过镜像生成容器,我们修改容器内的配置文件或者不修改也行,然后我们通过commit命令就可以实现,这时镜像的层数: 官网镜像的层数 + 我们的容器层 = 这个镜像的层数。
例如
docker commit -m=”提交的描述信息” -a=”作者” 容器id 目标镜像名 [TAG](TAG版本信息)
第二种方式,通过Dockerfile文件来构建自己的镜像
在自己创建镜像之前我们可以观看一下官网上镜像的构建过程
这是我们去官网上找到的,我们也可以下载官网的镜像通过history命令查看官网上镜像的构建过程
查看了官网镜像的构建过程,下一步我们自己构建镜像!
在构建自己的镜像之前,我们有必要说一下Dockerfile的语法
1、 每个保留关键字(指令)都必须是大写字母
2、 执行从上到下顺序执行
3、 #标识注释
4、 每一个指令都会创建提交一个新的镜像层,并提交!
dockerfile指令
#FROM 基础镜像,一切从这里构建
#MAINTAINER 镜像是谁写的, 姓名+邮箱
#RUN 镜像构建的时候需要运行的命令
#ADD 搭建一个tomcat镜像,则需要添加一个tomcat压缩包
#WORKDIR 镜像工作目录
#VOLUME 挂载的目录位置
#EXPOSE 暴露端口配置
#RUN
#CMD 指定这个容器启动的时候要运行的命令 只有最后一个会生效,可被替代
#ENTRYPOINT 指定这个容器启动的时候要运行的命令 可以追加命令
#ONBUILD 当构建一个被继承 dockerfile 这个时候就会运行ONBUILD 的指令—触发指令
#COPY 类似与ADD,将我们的文件拷贝到镜像中
#ENV 构建的时候设置环境变量
这些指令也有通俗的理解方式,下面是我在网上找到的照片
做一个简单测试,构建我们自己的centos
这个Dockerfile,我使用了centos的镜像,然后指定了工作目录,添加了vim和net相关的命令,因为官网的centos没有vim和ip addr等命令
然后通过build命令构建镜像
因为我之前构建过一次,第一次失败了,但是请注意,Step 2/10 到Step 5/10 这里面都是用的Using cache 所以并没有浪费我之前用的时间!
这里我们就有自己的镜像了,
然后通过run就可以启动我们自己的镜像了,
注意:
CMD 和ENTRYPOINT 的区别!
#CMD 指定这个容器启动的时候要运行的命令 只有最后一个会生效,可被替代。
#ENTRYPOINT 指定这个容器启动的时候要运行的命令 可以追加命令。
我们可以测试一下
1、编写dockerfile文件:
FROM centos
CMD [“ls”,“-a”]
2、Build 镜像
3、Run镜像
发现我们的命令生效了!
测试2
想追加一个 -l 命令
Docker run 刚才构建的镜像id -l
发现会报错:
因为CMD的情况下, -l 替换了CMD 【“ls”,“-a”】命令 而 -l不是命令所以报错!!
测试ENTRYPOINT
编写一个dockerfile文件
Build为镜像
然后使用docker run 镜像id:1.0 -l (添加 -l命令) 测试一下
发现ENTRYPOINT 命令确实是追加命令!
No.two
如何让别人获取我们的镜像,我们可以将我们的容器发布到Docker Hub 或者 阿里云
发布镜像到dockerHub
1、 注册账号 dockerhub
2、 确定账号可以登陆
3、 在我们服务器上提交自己的镜像
Docker login 命令
Options:
-p, --password string Password
–password-stdin Take the password from stdin
-u, --username string Username
登陆成功!
然后通过push命令发布我们的镜像
Docker push 镜像id:版本
发布到阿里云:
1、 登陆阿里云
2、 找到镜像服务
3、 创建一个命名空间
4、 创建容器镜像(创建本地仓库)
5、 浏览仓库镜像
其时阿里仓库已经给我们详细列出来我们怎么发布镜像到阿里云仓库了!
发布镜像之后,我们可以在阿里云仓库找到我们的镜像
No.three
docker默认的网络是docker0,因此我们可以首先要研究一下docker0是如何处理网络的
测试1、首先创建一个容器,然后通过exec命令进入命令
使用ip addr命令查看容器内网络!
发现容器内网络多了一个 42:eth0@if43: 这样的网络对!
我们也可以退出容器,在虚拟机上通过ip addr命令,查看一下虚拟机的网络!
发现虚拟机上也多了一个43:veth5be6ef@if42:这样的数据对。
我们可以试试通过ping 来测试一下,虚拟机能否ping通容器!
我们通过ip发现是可以ping通容器的!
**知识点:**1、 我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0,它默认使用桥接模式,使用的技术是evth-pair技术。
测试2、
再次启动一个容器
发现虚拟机上会又多一个网络对
然后我们测试一下这两个容器是否可以ping 通
发现我们使用ip ping 的时候是可以ping通的!!!
下面这个图可以帮我们方便理解
结论: tomcat01和tomcat02是公用的一个路由器docker0,所有的容器不指定网络的情况下,都是通过docker0路由的。Docker会给我们的容器分配一个默认的可用ip。Docker中所有的网络接口都是虚拟的,虚拟的转发效率高。并且只要删除docker容器,对应网桥对就没有了!
**思考:**我们生产环境是如何做到docker容器之间的通信的,因为docker关闭之后,再启动容器时,docker0会再重新分配一个ip给容器,这时,如何我们通过ip来让容器互联的话,岂不是要每次重启docker时,我们就要重新修改一下配置文件!!!这是不现实的!!!因此我们需要通过容器名字来让容器之间互联!!!
如何解决这个问题!
首先我们可以简单了解一下 --link命令
通过一下这个命令启动bins1
docker run -it -d -p –name=bins1 –link bins tomcat
然后我们通过ping命令
docker exec -it bins1 ping bins
发现bins1是可以ping通bins的
探究一下这个–link命令的原理:
首先进入容器,查看容器内的host文件
发现,这个–link好low他是通过在host文件中添加一个地址对,来指定,所以我们才可以通过bins1来访问bins
但是如果我们重启docker之后,容器的ip还是会变化,如果我们想通过容器名字,让容器互联的话,我们每次都需要通过–link命令来启动容器了,稍有疏忽就会使容器不能互联!
有没有一种更好的办法可以解决这个问题!
使用docker自定义网络就可以解决这个问题了!
所有的技术都是为了解决问题而出现的!
使用docker自定义网络解决前面出现的问题
首先:查看docker所有的网络
docker network ls
Brige:桥接模式,就是在docker上搭桥,比如:2想和3通信,则2通过1访问3
None:不配置网络,(不适用)
Host:主机模式,和宿主及共享网络
Container:容器网络连通!(用的少!局限很大)
自己创建也是使用brige模式!
我们需要了解,我们直接启动容器时,默认有这么一个操作:
docker run -d -P --name=bins --net bridge tomcat
也就是容器默认启动时,通过桥接模式启动的!
其次:我们编写自己的网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
–driver bridge //创建网络
–subnet 192.168.0.0/16 //配置子网
–gateway 192.168.0.1 //配置网关
通过inspect命令查看我们自定义网络的详细信息
通过我们自己的网络启动连个两个tomcat
再次查看我们的网络
docker inspect mynet
[
{
"Name": "mynet",
"Id": "465d76fe79280aa2747ddda73358af1d1e032c86c200097109cc5757378bacfa",
"Created": "2020-07-19T00:42:37.12993428+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"47e29a3ab9e8bed75835c75ebe1ecb987be09054b6291375a0b307178ca9f21f": {
"Name": "bins4",
"EndpointID": "3c68bdf50e0315ebbdaaec94d8a80f88ade6a480f8590622bf96067182726810",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
},
"f73d29c0151977b76ad27457c689fe228a5eaaf129080c0d20b5468c7ea1347b": {
"Name": "bins3",
"EndpointID": "902a30d77c03b62c60c8ec181bfb8929c15ed77bbb2e0139ec31e63ab680f09d",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
发现Containers中包含了两个容器。
再次ping两个容器
通过ip可以ping通
然后我们通过容器名字可以ping通吗?
wo,发现也可以ping通,
虽然我们自己定义的网络只是简单的设置了子网,网关,网络名字,但是自定义网络却自己帮我们解决了这个docker0没有解决的问题(通过容器名字互联)
**思考一下:**如何让连个不同网络的容器互联呢?
思路: 192.165.0.0网段上有个容器1,192.164.0.0网段上有个容器2
容器1想访问容器2需要做的是容器1和192.164.0.0网络打通,并不是直接让两个容器打通
通过–help命令我们可以查看network的一下扩展命令
通过connect命令就可以让容器和网络实现互联!
开始测试:
docker network connect mynet bins1
让在docker0网段上的bins1和mynet网段进行连通
然后通过inspect命令查看mynet网络
发现mynet网络上竟然多出来一个bins1,但是bins1也在docker0中,也就是一个容器两个ip来解决了这个问题。
通过3篇博客简单的介绍了Docker的使用,到目前为止,docker的基本操作我们就非常熟悉了,但是如果拿到生产上,还是远远不够的,我们还需要学习Docker compose,Docker swarm,K8s,持续集成等。
非常感谢kuang神老师的分享!!!