上一篇文章,我们学习了docker的基础操作,还是那句话,渴望升职加薪的我们怎么可能仅仅停留在基础上,那就来继续学习下docker的数据卷、DockerFile和Docker网络吧。文章课程链接:【狂神说Java】Docker最新超详细版教程通俗易懂
前面我们知道,我们启动一个镜像,就会生成一个容器,容器与外界隔离,我们的数据也在容器中,如果我们的容器是mysql,它将存储大量重要的数据,一不小心将mysql容器删除了,那我们的数据也将被一起被删除,因此,我们要解决删除容器时将数据一并删除的问题,而卷技术就能帮助我们解决这个问题,它将我们容器内的目录挂载到linux上,mysql容器中的数据就会自动同步到本地。
数据卷的功能包括
容器的数据持久化、数据同步、数据共享,数据同步可用于在linux主机修改容器内的配置文件(难得进到容器内修改),如nginx
命令行挂载
# -v 挂载
# docker run -it -v 主机目录:容器目录
docker run -it -v /home/cs:/home centos /bin/bash # 服务器的/home/cs目录挂载centos容器的/home目录
挂载后,两个目录就会相互同步了,可以通过命令查看是否挂载成功
# docker inspect 容器id
如图
配置好后,可以进行测试,在容器内相应目录添加内容或者在主机上相应目录添加内容,然后在对应的目录下查看是否同步
1、下载mysql镜像
docker pull mysql:5.7
docker images # 查看一下
2、运行容器(做数据挂载)
docker run -d -p 3310:3306 # -d:后台运行,-p:映射端口
-v /home/mysql/config:/etc/mysql/my.conf # -v:数据卷挂载
-v /home/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456 # -e 环境配置(mysql要设置密码)
--name mysql01 # --name 名字
mysql:5.7
3、测试
我们输入上述一串命令后,可以通过可视化工具连接mysql,看看是否成功,注意暴露的端口是3310,连接完成后,我们在工具上创建一个数据库test,然后到服务器相应的挂载目录,看下是否做到了同步
匿名挂载
docker run -d -P --name nginx01 -v /etc/nginx nginx
可以通过命令查看卷,匿名卷会自动生成一个字符串作为名字
docker volume ls
具名挂载
# 注意 juming-nginx前没有/,这是卷的名称
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
区别如图
匿名卷的名字是自动生成的一串字符,具名卷则是取的名字,如红框
查看卷的具体信息
#docker volume inspect 卷名称
docker volume inspect juming-nginx
效果如图,Mountpoint为卷的路径。所有docker容器内的卷,不指定目录时,就默认放到/var/lib/docker/volumes下
可以自己cd到这个目录下去看看,里面有许多的卷,然后继续cd到/juming-nginx/_data下,这里面就有我们前面挂载的nginx配置文件
小结
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
扩展
可以使用 ro/rw改变读写权限,ro代表只读,rw可读写,默认为rw,当为ro时,只运行宿主机操作,容器内只可读
docker run -d -P --name nginx01 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
DockerFile是用来构建docker镜像的构建文件,前面我们用commit的方式生成过镜像,DockerFile也是一种生成镜像的方式,这里只简单谈谈,后续进行学习
1、创建一个DockerFile
FROM centos
VOLUME [“volume01”,“volume02”]
CMD echo “-----end-----”
CMD /bin/bash
2、执行命令
docker build -f dockerfile1 -t kuangshen-centos:1.0 .
注意:命令后有一个点,名称叫 kuangshen-centos,视频教程的截图为kuangshen/centos
执行这个命令后,出现这个界面,分别对应dockerfile1的四行命令,获取centos基础容器,挂载两个卷,输出–end–,进入到bin bash
执行完毕后可以通过docker images 查看下是否生成镜像
3、测试
docker run -it 5fe09wju23 /bin/bash
然后会发现,我们前面挂载的两个卷会生成进来,如图
也可以通过 docker inspect 容器id 查看,如图
前面,我们讲到了数据卷可用于容器间数据的同步,下面就开始学习
我们会启动三个容器,以达到测试数据同步的目的,其中,被挂载的容器称为父容器(数据卷容器),其他容器通过挂载它,进行数据间的同步
# 这里启动的是 “(四)数据卷—DockerFile ”中构建的镜像
docker run -it --name docker01 fs88ewj43e09
# 容器启动后都查看下是否有数据卷
ls -l
# 退出当前容器 ctrl + p + Q
# 通过 --volumes-from 容器名称,挂载父容器,这里是docker01
docker run -it --name docker02 --volumes-from docker01 fs88ewj43e09
# 创建第三个
docker run -it --name docker03 --volumes-from docker01 fs88ewj43e09
新增文件:我们在docker01的数据卷中创建一个文件,然后在docker02和03查看是否同步,相同的,也在docker02/03操作,看是否在另外两个容器中同步
删除容器:我们删除docker01,查看docker02/03数据卷中的数据是否正常,答案是肯定的,这里不记录演示过程
通过删除docker01,我们发现docker02/03的数据还存在,这说明容器卷之间的数据同步是拷贝的方式(双向),而不是同一个,就像java对象,是新new出来的
使用场景:容器间配置文件或者数据文件的同步
前面,我们接触了DockerFile,知道它是构建镜像的文件,是一个命令参数脚本,其构建步骤为
首先,我们看看官方是怎么做的,我们进入DockerHub,然后搜索一个镜像,这里,我搜索的是centos,如图
随便点击一个版本进入,比如centos7,然后我们就会进入到github了,这里给我们提供了一个DockerFile文件(官方提供的大多是基础包),如图
代码如下
FROM scratch # DockerHub 99%的镜像都从这个基础镜像过来的
ADD centos-7-x86_64-docker.tar.xz / # 添加一个centos7
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"] # 运行
在构建前,我们先学习下构建基础
DockerFile是面向开发的,发布一个项目,做镜像,就需要编写DockerFile文件
FROM 基础镜像,一切从这里开始构建
MAINTAINER 镜像是谁写的,国际常用:姓名+邮箱
RUN 镜像构建时需要执行的命令
ADD 加点东西,比如我们构建的是centos,给它加个mysql镜像啥的
WORKDIR 镜像的工作目录
VOLUME 挂载的目录
EXPOSE 指定暴露的端口
CMD 指定这个容器启动的时候要运行的命令,只有最后一个生效,可被替代
ENTRYPOINT 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD 当构建一个被继承 DockerFile,这个时候会执行ONBUILD命令
COPY 类型ADD,将文件拷贝到镜像中
ENV 构建镜像时设置环境变量,前面mysql需密码有使用
前面我们说到他们的区别
CMD 指定这个容器启动的时候要运行的命令,只有最后一个生效,可被替代
ENTRYPOINT 指定这个容器启动的时候要运行的命令,可以追加命令
这里,我们来实际演示下,加深理解,首先构建CMD的DockerFile
FROM centos
CMD ["ls","-a"]
docker build -f dockerfile-cmd-test -t cmdtest .
docker run 66rwrh3d3rs
你会发现,执行了ls -a,展示了所有的目录
而当我们这样操作时,就会报错了,这里就不记录过程了
docker run 66rwrh3d3rs -l
这是由于CMD下 -l 替换了ls -a,-l 不是命令,因此报错了,这样才不会错
docker run 66rwrh3d3rs ls -al
看到这里,你已经能够理解他们的区别了,我们在写一个ENTRYPOINT的,步骤跟前面的一样,细节不在记录
FROM centos
ENTRYPOINT ["ls","-a"]
然后直接执行,
docker run 7fsh6wgded -l
你会发现不报错,这就很直观的展示了他们之前的区别
官方的都是阉割版,我们来构建一个相对完整的,加上vim命令和ifconfig等命令
FROM centos
MAINTAINER zx<8208820@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo SMYPATH
CMD echo "---end---"
CMD /bin/bash
# 注意,后面有个点
docker build -f mydockerfile-centos -t mycentos:0.1 .
然后就会一步一步执行了,具体可查看 “(四)数据卷—DockerFile”
执行完成后,也可以通过如下命令查看构建过程
docker history 镜像id
docker run -it mycentos:0.1
然后执行pwd、vim、ifconfig等命令,发现能够执行
FROM centos
MAINTAINER zx<8208820@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8ull-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.22.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV 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
CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out
docker build -t diytomcat .
docker run -d -p 9090:8080 --name mytomcat
-v /home/mytomcat/test:/usr/local/apache-tomcat-9.0.22/webapps/test
-v /home/mytomcat/logs:/usr/local/apache-tomcat-9.0.22/logs
diytomcat
# 进入容器
docker exec -it 6fsj3jrwda78 /bin/bash
# 进来就是工作目录,然后查看下是否有tomcat等
ls
http://ip:9090
然后我们可以写一个jsp放到webapps的test下,查看能否访问页面,由于我们已经挂载好,因此可以在容器外对应的目录编写,具体测试过程就不记录了
# docker login -u 账号
# 根据提示输入密码
# 登录后,输入命令
docker push zx/diytomcat:1.0
这样就可以完成发布了,阿里云发布就不记录了
贴张百度的图,图片内容包含了我们前面学习的所有内容,生动展示了他们之间的转换关系
在这部分我们只做简单了解,不记录详细过程,由于计算机网络知识不扎实,可能存在错误 >_<
我们前面讲到,docker容器是独立的,当我们两个容器间需要通信时,比如tomcat中的java应用要使用数据库,我们的tomcat和mysql又是独立的两个容器,他们之间是如何通讯的呐,这就是docker的网络
通过测试,我们得出两个结论
1、主机能够ping通主机内的容器
2、同一主机内的两个容器之间能够相互ping通
这是如何做到的,如图
当我们启动容器时,docker会自动帮我们生成一对网卡(veth-pair技术),如图,261和262,容器间不直接通信,而是通过网卡连接路由器docker0,docker0充当桥梁,将它们连接起来,所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip
什么是–link,在我们启动一个容器时,docker会给我们自动分配可用ip,如果我们在项目中配置了数据库的dataSource(ip:端口 库名等),现在我们不用以前的数据库了,重新启动一个mysql容器,那么ip就换了,我们需要在项目中去改动,就很麻烦,因此,我们需要一种机制帮我们解决这个问题,就是将ip改成容器名称来进行连接(其本质为hosts映射),因为名字我们可以固定
我们启动两个容器,用docker分配的ip是能ping通的,但直接使用容器名称是不通的,我们需要在启动容器时加上–link,如下
docker run -d -P --name tomcat03 --link tomcat02 mysql
这样通过名称就能ping通了,他是如何实现的,如图
在docker03的hosts文件中,看到了如下配置 172.18.0.3 tomcat02 31285***,这就是我们能够ping通的原因了
注意,这只能实现tomcat03到tomcat02,tomcat02 ping tomcat03是不通的,我们要想ping通还得在02的hosts加上03的映射地址,当然–link的方式是不建议使用的,我们需要的是自义定网络
bridge:桥接 docker默认,自己创建也使用bridge模式
none:不配置网络
host:和宿主机共享网络
container:容器网络连通!(用得少,局限很大)
在创建前,我们要保证环境干净,删除掉前面测试的网络等
docker rm -f $(docker ps -aq)
删除后,查看下网卡,初始的话只有三个网卡 ip addr
前面我们在启动容器时,我们省略了网络配置,网络配置命令如下
# --net bridge为配置网络,bridge就是前面我们说到的默认网络:docker0,
docker run -d -P --name tomcat01 --net bridge tomcat
docker0的特点是:默认,域名不能访问,需要–link打通
因此,我们需要自定义一个网络,可以通过 docker network create --help 查看创建网络相关命令,创建网络
# --driver bridge 桥接 默认
# --subnet 192.168.0.0/16 子网地址
# --gateway 192.168.0.1 网关地址
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
然后就可以通过 docker network ps 查看到我们配置的网络了
我们需要启动两个容器,并配置我们自定义的网络
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
查看自定义网络的详细信息
docker network inspect mynet
docker exec -it tomcat-net-01 ping 192.168.0.3
docker exec -it tomcat-net-01 ping tomcat-net-02
发现两个都能够ping通,而不是我们前面的要使用–link才能通了,这是因为自定义网络,docker都已经帮我们维护好了对应的关系,推荐使用自定义网络
自定义网络的好处有:当我们搭建redis集群和mysql集群时,使用不同的网络,保证集群的安全和健康
前面我们讲到同一网络间的容器是能通的,但是不同网络间的容器呐,答案肯定是不通,因为他们之间的网段都是不一致的,如图,下面我们将学习怎样把docker0和mynet打通,开始前先在docker0下启动两个容器
docker run -d -P --name tomcat01 tomcat / docker run -d -P --name tomcat02 tomcat
打通的命令为 connet,可以通过 docker network connect --help 查看详细,连通命令
docker network connect mynet tomcat01
# 连通后,其实就是将 tomcat01放到了mynet下(一个容器,两个ip)
然后,我们的tomcat01 就能 ping 通tomcat-net-01了,假设我们要跨网络操作别人,就需要使用 docker network connect 连通了
docker network create redis --subnet 172.38.0.0/16
6372:6379 16372:16379 redis-2 172.38.0.12
6373:6379 16373:16379 redis-3 172.38.0.13
…
创建6个redis后,使用docker ps查看下
# 和其他不一样,redis没有bash,对应的是sh
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
然后根据提示输入yes即可,可以通过如下命令查看是否配置成功
redis-cli -c
cluster info
cluster nodes
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
docker build -t springboot_test .
执行完毕后,docker images,就出现了springboot_test这个镜像
docker run -d -P --name springboot_docker springboot_test
# 执行完毕看看是否成功
docker ps
# curl localhost:端口/api
前面的知识,我们只是做了简单的应用和测试,真正的企业运用,我们还需要继续学习
Docker Compose
Docker Swarm
CI/CD之Jenkins
这些内容等到需要的时候在进行学习啦
**如果总结的还行,就点个赞呗 @_@ 如有错误,欢迎指点!