Docker学习——docker高级

Docker高级

  • 前言
  • 一、Docker数据卷
    • (一)什么是容器数据卷
    • 使用数据卷
    • (二)实践-安装Mysql
    • (三)具名挂载和匿名挂载
    • (四)数据卷—DockerFile
    • (五)、数据卷容器
  • 二、DockerFile制作镜像
    • (一)、DockerFile介绍
    • (二)、DockerFile基础
      • DockerFile指令
      • CMD和ENTRYPOINT的区别
    • (三)、构建DockerFile实例
      • 构建centos
      • 构建Tomcat
    • (四)、总结
  • 三、Docker网络
    • (一)、基础原理
    • (二)、--link
    • (三)、自定义网络
      • 创建自定义网络
      • 测试
      • 网络连通
  • 四、Docker实战
    • Redis集群部署实战
    • SpringBoot微服务打包Docker镜像
    • 补充
  • end...

前言

上一篇文章,我们学习了docker的基础操作,还是那句话,渴望升职加薪的我们怎么可能仅仅停留在基础上,那就来继续学习下docker的数据卷、DockerFile和Docker网络吧。文章课程链接:【狂神说Java】Docker最新超详细版教程通俗易懂

一、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

如图
Docker学习——docker高级_第1张图片
配置好后,可以进行测试,在容器内相应目录添加内容或者在主机上相应目录添加内容,然后在对应的目录下查看是否同步

(二)实践-安装Mysql

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学习——docker高级_第2张图片
匿名卷的名字是自动生成的一串字符,具名卷则是取的名字,如红框

查看卷的具体信息

#docker volume inspect 卷名称
docker volume inspect juming-nginx

效果如图,Mountpoint为卷的路径。所有docker容器内的卷,不指定目录时,就默认放到/var/lib/docker/volumes下
Docker学习——docker高级_第3张图片
可以自己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

DockerFile是用来构建docker镜像的构建文件,前面我们用commit的方式生成过镜像,DockerFile也是一种生成镜像的方式,这里只简单谈谈,后续进行学习
1、创建一个DockerFile

  • 创建目录 mkdir docker-test-volume
  • 创建文件 vim dockerfile1,写入内容保存退出,注意都为大写

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学习——docker高级_第4张图片
执行完毕后可以通过docker images 查看下是否生成镜像

3、测试

  • 启动镜像

docker run -it 5fe09wju23 /bin/bash

然后会发现,我们前面挂载的两个卷会生成进来,如图
Docker学习——docker高级_第5张图片
也可以通过 docker inspect 容器id 查看,如图
Docker学习——docker高级_第6张图片

  • 测试卷同步
    这里跟前面的方式一样,不再记录

(五)、数据卷容器

前面,我们讲到了数据卷可用于容器间数据的同步,下面就开始学习
我们会启动三个容器,以达到测试数据同步的目的,其中,被挂载的容器称为父容器(数据卷容器),其他容器通过挂载它,进行数据间的同步

  1. 启动三个容器
# 这里启动的是 “(四)数据卷—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
  1. 测试

新增文件:我们在docker01的数据卷中创建一个文件,然后在docker02和03查看是否同步,相同的,也在docker02/03操作,看是否在另外两个容器中同步
删除容器:我们删除docker01,查看docker02/03数据卷中的数据是否正常,答案是肯定的,这里不记录演示过程

  1. 总结

通过删除docker01,我们发现docker02/03的数据还存在,这说明容器卷之间的数据同步是拷贝的方式(双向),而不是同一个,就像java对象,是新new出来的
使用场景:容器间配置文件或者数据文件的同步

二、DockerFile制作镜像

(一)、DockerFile介绍

前面,我们接触了DockerFile,知道它是构建镜像的文件,是一个命令参数脚本,其构建步骤为

  • 编写一个dockerFile文件
  • docker build 构建成为一个镜像
  • docker run 运行镜像
  • docker push 发布镜像,可发布到DockerHub、阿里云镜像仓库

首先,我们看看官方是怎么做的,我们进入DockerHub,然后搜索一个镜像,这里,我搜索的是centos,如图
Docker学习——docker高级_第7张图片
随便点击一个版本进入,比如centos7,然后我们就会进入到github了,这里给我们提供了一个DockerFile文件(官方提供的大多是基础包),如图
Docker学习——docker高级_第8张图片
代码如下

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基础

在构建前,我们先学习下构建基础

  1. 保留关键字(指令),都是大写字母
  2. 执行从上到下顺序执行
  3. #为注释
  4. 每一个指令都会创建提交一个新的镜像层

DockerFile是面向开发的,发布一个项目,做镜像,就需要编写DockerFile文件

DockerFile指令

这里先贴张图
Docker学习——docker高级_第9张图片

FROM 基础镜像,一切从这里开始构建
MAINTAINER 镜像是谁写的,国际常用:姓名+邮箱
RUN 镜像构建时需要执行的命令
ADD 加点东西,比如我们构建的是centos,给它加个mysql镜像啥的
WORKDIR 镜像的工作目录
VOLUME 挂载的目录
EXPOSE 指定暴露的端口
CMD 指定这个容器启动的时候要运行的命令,只有最后一个生效,可被替代
ENTRYPOINT 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD 当构建一个被继承 DockerFile,这个时候会执行ONBUILD命令
COPY 类型ADD,将文件拷贝到镜像中
ENV 构建镜像时设置环境变量,前面mysql需密码有使用

CMD和ENTRYPOINT的区别

前面我们说到他们的区别

CMD 指定这个容器启动的时候要运行的命令,只有最后一个生效,可被替代
ENTRYPOINT 指定这个容器启动的时候要运行的命令,可以追加命令

这里,我们来实际演示下,加深理解,首先构建CMD的DockerFile

  1. 创建文件 vim dockerfile-cmd-test 写入内容
FROM centos
CMD ["ls","-a"]
  1. 执行构建
docker build -f dockerfile-cmd-test -t cmdtest .
  1. 运行
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

你会发现不报错,这就很直观的展示了他们之前的区别

(三)、构建DockerFile实例

构建centos

官方的都是阉割版,我们来构建一个相对完整的,加上vim命令和ifconfig等命令

  1. 创建一个DockerFile,取名mydockerfile-centos,写入以下内容
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
  1. 构建DockerFile,执行命令
# 注意,后面有个点
docker build -f mydockerfile-centos -t mycentos:0.1 .

然后就会一步一步执行了,具体可查看 “(四)数据卷—DockerFile”
执行完成后,也可以通过如下命令查看构建过程

docker history 镜像id

  1. 运行容器
docker run -it mycentos:0.1

然后执行pwd、vim、ifconfig等命令,发现能够执行

构建Tomcat

  1. 准备镜像文件 tomcat的压缩包和jdk的压缩包
  2. 在同级目录创建一个DockerFile,取名Dockerfile,这是官方推荐的名称,build构建时就不需要写 -f 了,然后写入内容
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
  1. 构建镜像
    由于我们的Dockerfile的名字为官方定义(默认的),这里可以不用写名字
docker build -t diytomcat .
  1. 运行容器
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
  1. 访问测试
    在浏览器访问tomcat地址,进入到tomcat页面表示成功

http://ip:9090

然后我们可以写一个jsp放到webapps的test下,查看能否访问页面,由于我们已经挂载好,因此可以在容器外对应的目录编写,具体测试过程就不记录了

  1. 发布镜像(dockerHub)
    注册账号,网站地址:https://hub.docker.com/,并登录
    发布我们的镜像
# docker login -u 账号
# 根据提示输入密码
# 登录后,输入命令
docker push zx/diytomcat:1.0

这样就可以完成发布了,阿里云发布就不记录了

(四)、总结

贴张百度的图,图片内容包含了我们前面学习的所有内容,生动展示了他们之间的转换关系
Docker学习——docker高级_第10张图片

三、Docker网络

(一)、基础原理

在这部分我们只做简单了解,不记录详细过程,由于计算机网络知识不扎实,可能存在错误 >_<
我们前面讲到,docker容器是独立的,当我们两个容器间需要通信时,比如tomcat中的java应用要使用数据库,我们的tomcat和mysql又是独立的两个容器,他们之间是如何通讯的呐,这就是docker的网络
通过测试,我们得出两个结论

1、主机能够ping通主机内的容器
2、同一主机内的两个容器之间能够相互ping通

这是如何做到的,如图
Docker学习——docker高级_第11张图片
当我们启动容器时,docker会自动帮我们生成一对网卡(veth-pair技术),如图,261和262,容器间不直接通信,而是通过网卡连接路由器docker0,docker0充当桥梁,将它们连接起来,所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip

(二)、–link

什么是–link,在我们启动一个容器时,docker会给我们自动分配可用ip,如果我们在项目中配置了数据库的dataSource(ip:端口 库名等),现在我们不用以前的数据库了,重新启动一个mysql容器,那么ip就换了,我们需要在项目中去改动,就很麻烦,因此,我们需要一种机制帮我们解决这个问题,就是将ip改成容器名称来进行连接(其本质为hosts映射),因为名字我们可以固定
我们启动两个容器,用docker分配的ip是能ping通的,但直接使用容器名称是不通的,我们需要在启动容器时加上–link,如下

docker run -d -P --name tomcat03 --link tomcat02 mysql

这样通过名称就能ping通了,他是如何实现的,如图
Docker学习——docker高级_第12张图片
在docker03的hosts文件中,看到了如下配置 172.18.0.3 tomcat02 31285***,这就是我们能够ping通的原因了
注意,这只能实现tomcat03到tomcat02,tomcat02 ping tomcat03是不通的,我们要想ping通还得在02的hosts加上03的映射地址,当然–link的方式是不建议使用的,我们需要的是自义定网络

(三)、自定义网络

首先我们查看下docker的网络信息
Docker学习——docker高级_第13张图片

bridge:桥接 docker默认,自己创建也使用bridge模式
none:不配置网络
host:和宿主机共享网络
container:容器网络连通!(用得少,局限很大)

创建自定义网络

在创建前,我们要保证环境干净,删除掉前面测试的网络等

docker rm -f $(docker ps -aq)

删除后,查看下网卡,初始的话只有三个网卡 ip addr
Docker学习——docker高级_第14张图片
前面我们在启动容器时,我们省略了网络配置,网络配置命令如下

# --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学习——docker高级_第15张图片
然后测试两个容器的网络

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
Docker学习——docker高级_第16张图片
打通的命令为 connet,可以通过 docker network connect --help 查看详细,连通命令

docker network connect mynet tomcat01
# 连通后,其实就是将 tomcat01放到了mynet下(一个容器,两个ip)

然后,我们的tomcat01 就能 ping 通tomcat-net-01了,假设我们要跨网络操作别人,就需要使用 docker network connect 连通了

四、Docker实战

Redis集群部署实战

部署如图所示的Redis集群
Docker学习——docker高级_第17张图片

  1. 首先创建Redis集群的网络
docker network create redis --subnet 172.38.0.0/16
  1. 使用脚本创建6个redis配置
    Docker学习——docker高级_第18张图片
    这里只简单记录下过程,直接粘贴如图脚本然后回车执行即可,执行完后,可以通过这个步骤查看是否成功
    Docker学习——docker高级_第19张图片
  2. 启动redis
    在这里插入图片描述
    然后依次启动剩下的五个redis,注意对外端口、名称、ip都要改变,依次为

6372:6379 16372:16379 redis-2 172.38.0.12
6373:6379 16373:16379 redis-3 172.38.0.13

创建6个redis后,使用docker ps查看下

  1. 创建集群
    先进入到redis-1中
# 和其他不一样,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

如图
Docker学习——docker高级_第20张图片

  1. 测试集群
    过程:先往redis中设置一个值,然后将存储节点容器给删除,然后看能否正常取到该值,如图
    Docker学习——docker高级_第21张图片
    先设置一个值,set a b,工作的redis为14这个,然后我们在另外一个主机窗口将此容器删除,然后再获取值,发现能够正常获取到,说明我们的集群是部署成功的,我们通过 cluster nodes也可以看到这个过程,13出问题了,然后14成为了master

SpringBoot微服务打包Docker镜像

  1. 在IDEA上创建一个springboot项目
    自己创建一个,然后写个controller接口,能够测试访问即可
  2. 打包应用
    maven -> package 打包即可,然后在cmd中看下能不能运行,java -jar xxx.jar
  3. 编写dockerfile
FROM java:8

COPY *.jar /app.jar

CMD ["--server.port=8080"]

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app.jar"]
  1. 构建镜像
    先在服务器上创建一个目录:idea,将我们的jar包和dockerfile上传到目录中,然后执行
docker build -t springboot_test .

执行完毕后,docker images,就出现了springboot_test这个镜像

  1. 发布运行
docker run -d -P --name springboot_docker springboot_test
# 执行完毕看看是否成功
docker ps
  1. 测试
    访问我们设计好的controller接口,如果正确返回则成功,当然浏览器访问也可以
# curl localhost:端口/api

补充

前面的知识,我们只是做了简单的应用和测试,真正的企业运用,我们还需要继续学习
Docker Compose
Docker Swarm
CI/CD之Jenkins
这些内容等到需要的时候在进行学习啦

end…

**如果总结的还行,就点个赞呗 @_@ 如有错误,欢迎指点!

你可能感兴趣的:(中间件/工具,docker,容器,运维)