容器数据卷 什么是容器数据卷 Docker的理念回顾
将应用和环境打包成一个镜像,可以快速部署在不同的平台。
问题:如果数据都在容器中,那么如果我们删除容器,数据就会丢失!
需求:数据可持续化,数据可以存储在宿主机。
引入:容器之间可以有一个数据共享的技术,Docker容器中产生的数据,同步到宿主机,这就是容器数据卷技术。
总结:将容器内的目录挂载在宿主机上,实现容器数据的持久化和同步操作,容器间的数据共享。
使用数据卷 挂载数据卷方式1:运行容器时直接使用命令 -v来挂载
docker run -it -v 主机目录:容器目录 # 测试 [root@xizou /]# cd /home/ [root@xizou home]# ls [root@xizou home]# docker run -it -v /home/ceshi:/home centos /bin/bash # Ctrl +p +q退出容器 [root@xizou /]# cd /home/ [root@xizou home]# ls ceshi # 可以通过 docker inspect 容器id 查看容器挂载信息
测试文件的同步
就算容器停止,宿主机上修改文件,修改后的文件也能同步到容器内。
实战:安装MySQL 思考:MySQL的数据持久化的问题
# 获取镜像 [root@xizou /]# docker pull mysql:5.7 # 运行容器,需要做数据挂载,安装MySql上需要配置密码,参考Docker Hub的官方指令 docker run --name some-mysql -v /my/custom:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag # docker run 命令 -d 后台运行 -p 端口映射 -v 卷挂载 -e 环境配置 --name 容器名字 [root@xizou /]# 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 4dc2e63a55e463168c39249dd4c4cdec2a1d43a1c4fa6f9045da2dd4099fa3a9 # 启动成功之后,就可以使用 Navicat Premium 或任意数据库连接软件远程连接到容器内的MySQL # Navicat Premium - 连接到服务器的3310端口 -- 服务器的3310端口与容器内的3306端口映射,因此就能连接到服务器启动的容器内部的MySQL # 在Navicat Premium创建一个数据库test ,可以发现服务器/home/mysql/data目录下会多一个test 目录,并且容器内/var/lib/mysql目录下也会多一个test 目录
将容器删除,发现挂载到服务器的数据卷依旧没有丢失,这体现了容器数据持久化功能。
具名挂载和匿名挂载 # 匿名挂载 -v 容器内路径 [root@xizou /]# docker run -d -P --name nginx01 -v /etc/nginx nginx e5b3b9b6b45b916a91ab149604bea917995cdea321ba3158be51503010624c90 # 查看容器卷的情况 [root@xizou /]# docker volume ls DRIVER VOLUME NAME local 18ae53d1715fed2dd0250ae1dc8ab0a5a06bd6efcf801f7c46e9ed9bd7ffdd3d # 这种就是匿名挂载,在 -v 只写了容器内的路径,没有写容器外的路径 # 具名挂载 [root@xizou /]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx dbcd1852923d857b825f9afff4429e79c29617e45402ae54e12b8861638c1c7e [root@xizou /]# docker volume ls DRIVER VOLUME NAME local 18ae53d1715fed2dd0250ae1dc8ab0a5a06bd6efcf801f7c46e9ed9bd7ffdd3d local juming-nginx # 通过 -v 卷名:容器内路径 # 查看该卷 [root@xizou /]# docker volume inspect juming-nginx [ { "CreatedAt": "2022-10-30T16:53:03+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data", "Name": "juming-nginx", "Options": null, "Scope": "local" } ] [root@xizou /]# cd /var/lib/docker/volumes/juming-nginx/_data/ [root@xizou _data]# ls conf.d mime.types nginx.conf uwsgi_params fastcgi_params modules scgi_params
所有的Docker容器内的卷,没有指定宿主机目录的情况下都是放在宿主机的 /var/lib/docker/volumes/xxx/_data
下。
通过具名挂载可以方便的找到我们的一个卷,大多数情况下使用具名挂载 。
# 如何区分具名挂载和匿名挂载 -v 容器内路径 # 匿名挂载 -v 卷名:容器内路径 # 具名挂载 -v /宿主机路径:容器内路径 # 指定路径挂载
拓展
# 通过 -v 容器内路径,ro、rw改变读写权限 ro readonly # 只读 rw readwrite # 可读可写 docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx # ro说明该路径的文件只能通过宿主机来改变,容器内部无法操作
初始Dockerfile Dockerfile是用来构建Docker镜像的构建文件。
挂载数据卷方式2:Dockerfile文件内定义
如,创建一个dockerfile1文件,内容为:
FROM centosVOLUME ["volume01" , "volume02" ] CMD echo "----end----" CMD /bin/bash
生成镜像
[root@xizou docker-test-volume]# docker build -f dockerfile1 -t xizou/centos:1.0 . Sending build context to Docker daemon 2.048kB Step 1/4 : FROM centos ---> 5d0da3dc9764 Step 2/4 : VOLUME ["volume01", "volume02"] ---> Running in 6cc1bc751006 Removing intermediate container 6cc1bc751006 ---> f3475e56ea65 Step 3/4 : CMD echo "----end----" ---> Running in 3eeb578f3d3d Removing intermediate container 3eeb578f3d3d ---> 3db916284cfc Step 4/4 : CMD /bin/bash ---> Running in d0b660ad310f Removing intermediate container d0b660ad310f ---> ee034a44e231 Successfully built ee034a44e231 Successfully tagged xizou/centos:1.0 [root@xizou docker-test-volume]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE xizou/centos 1.0 ee034a44e231 27 seconds ago 231MB tomcat02 1.0 600af0d3c7c9 20 hours ago 684MB elasticsearch 8.4.3 ce2b9dc7fe85 3 weeks ago 1.26GB nginx latest 605c77e624dd 10 months ago 141MB # 运行容器 [root@xizou docker-test-volume]# docker run -it ee034a44e231 /bin/bash [root@6d21590582da /]# ls -l total 56 lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin drwxr-xr-x 5 root root 360 Oct 30 09:23 dev drwxr-xr-x 1 root root 4096 Oct 30 09:23 etc drwxr-xr-x 2 root root 4096 Nov 3 2020 home lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64 drwx------ 2 root root 4096 Sep 15 2021 lost+found drwxr-xr-x 2 root root 4096 Nov 3 2020 media drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt drwxr-xr-x 2 root root 4096 Nov 3 2020 opt dr-xr-xr-x 130 root root 0 Oct 30 09:23 proc dr-xr-x--- 2 root root 4096 Sep 15 2021 root drwxr-xr-x 11 root root 4096 Sep 15 2021 run lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Nov 3 2020 srv dr-xr-xr-x 13 root root 0 Oct 30 09:23 sys drwxrwxrwt 7 root root 4096 Sep 15 2021 tmp drwxr-xr-x 12 root root 4096 Sep 15 2021 usr drwxr-xr-x 20 root root 4096 Sep 15 2021 var drwxr-xr-x 2 root root 4096 Oct 30 09:23 volume01 drwxr-xr-x 2 root root 4096 Oct 30 09:23 volume02 # 可以看见生成挂载的两个数据卷目录 volume01和volume02
验证:这个卷和外部一定有一个同步的目录
在容器的volume01内创建一个container.txt文件
[root@09423fb0f1d5 /]# cd volume01/ [root@09423fb0f1d5 volume01]# ls [root@09423fb0f1d5 volume01]# touch container.txt [root@09423fb0f1d5 volume01]# ls container.txt
查看下卷挂载的路径 docker inspect 容器id,如可以看到信息:
[root@xizou /]# cd /var/lib/docker/volumes/6fc2791f3e981e53c16a71d17d36c8279fda6210956603e69c9f75ccc9c0669c/_data [root@xizou _data]# ls container.txt
容器间数据共享实现多个MySQL数据同步。
启动第1个容器docker01
启动第2个容器docker02,数据卷继承自docker01,docker01成为数据卷容器。
docker run -it --name docker02 --volumes-from docker01 xizou/centos:1.0
删掉容器docker01,docker02依旧可以访问数据卷。数据卷之间是拷贝的概念。
多个MySQL实现数据共享
[root@xizou /]# docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 [root@xizou /]# docker run -d -p 3311:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
结论 :
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦持久化到了本地,本地的数据是不会自动删除的。
Dockerfile Dockerfile介绍 Dockerfile是用来构建Docker镜像的文件,是一个命令参数脚本文件。
构建步骤 :
1、编写Dockerfile文件
2、docker build构建为一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(Docker Hub、阿里云镜像仓库)
示例:CentOS7的Dockerfile文件,点击tag可跳转到Github,看到其Dockerfile文件。
很多官方镜像都是基础包,很多功能没有,通常需要自己搭建自己的镜像。
Dockerfile构建过程 基础知识:
1、每个保留关键字(指令)都必须是大写字母
2、执行从上到下顺序执行
3、#表示注释
4、每一个指令都会创建和提交一个镜像层
Dockerfile是面向开发的,发布项目制作镜像就需要写Dockerfile文件,Docker镜像逐渐成为企业交付的标准,必须掌握。
Dockerfile:构建文件,定义了一切的步骤,源代码,用来构建镜像。
Docker镜像:发布和运行的产品,可以通过commit指令或Dockerfile来制作。
Docker容器:镜像运行起来提供服务的服务器。
Dockerfile命令 FROM MAINTAINER RUN ADD WORKDIR VOLUME EXPOSE CMD ENTRYPOINT ONBUILD COPY ENV
Dockerfile实战 Docker Hub 中大部分镜像是从基础镜像 scratch
开始的,然后配置需要的软件来进行构建的。
创建自己的CentOS镜像
CentOS镜像默认的根目录为/,且没有ifconfig
# 1. 编写Dockerfile镜像 [root@xizou dockerfile]# cat mydockerfile-centos FROM centos:7 MAINTAINER xizou<xiongbinzou@163.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] . [root@xizou dockerfile]# docker build -f mydockerfile-centos -t centos:0.1 . # 构建成功 ..... Successfully built 0fc60a3f44de Successfully tagged mycentos:0.1 [root@xizou dockerfile]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mycentos 0.1 0fc60a3f44de 2 minutes ago 626MB # 3. 测试运行,发现默认目录变更且ifconfig和vim指令都能够支持 [root@xizou ~]# docker run -it mycentos:0.1 [root@c7cad6e52fd3 local]# pwd /usr/local [root@c7cad6e52fd3 local]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.3 netmask 255.255.0.0 broadcast 172.17.255.255 ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet) RX packets 8 bytes 656 (656.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [root@c7cad6e52fd3 local]# vim --help VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Dec 15 2020 16:44:08) usage: vim [arguments] [file ..] edit specified file(s) or: vim [arguments] - read text from stdin or: vim [arguments] -t tag edit file where tag is defined or: vim [arguments] -q [errorfile] edit file with first error # 4. 查看指定image构建历史(先回到宿主机) [root@xizou dockerfile]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mycentos 0.1 0fc60a3f44de 2 hours ago 626MB xizou/centos 1.0 ee034a44e231 5 hours ago 231MB tomcat02 1.0 600af0d3c7c9 24 hours ago 684MB [root@xizou dockerfile]# docker history 0fc60a3f44de IMAGE CREATED CREATED BY SIZE COMMENT 0fc60a3f44de 2 hours ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B 87d94a5cd7db 2 hours ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B 701f4da62eda 2 hours ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B a28bd4c7b6d4 2 hours ago /bin/sh -c #(nop) EXPOSE 80 0B 15d49edff70d 2 hours ago /bin/sh -c yum -y install net-tools 183MB 565a95d30b44 2 hours ago /bin/sh -c yum -y install vim 238MB 1dda317404d4 2 hours ago /bin/sh -c #(nop) WORKDIR /usr/local 0B ca7984844f10 2 hours ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0B 6e566e3aace3 2 hours ago /bin/sh -c #(nop) MAINTAINER xizou<xiongbin… 0B eeb6ee3f44bd 13 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 13 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B <missing> 13 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
拿到一个镜像后,可以通过docker history 镜像id查看镜像的构建历史,分析该镜像Dockerfile文件的组成。
CMD和ENREYPOINT的区别
测试 CMD 命令
# 1.进入文件 [root@xizou /]# cd /home/dockerfile/ # 2.创建dockerfile [root@xizou dockerfile]# cat dockerfile-cmd-test FROM centos:7 CMD ["ls","-a"] # 3.构建镜像 [root@xizou dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest . Sending build context to Docker daemon 3.072kB Step 1/2 : FROM centos:7 ---> eeb6ee3f44bd Step 2/2 : CMD ["ls","-a"] ---> Running in 850c034e822a Removing intermediate container 850c034e822a ---> 0b3e53a3ddc6 Successfully built 0b3e53a3ddc6 Successfully tagged cmdtest:latest # 4.运行,发现 ls -a 命令生效 [root@xizou dockerfile]# docker run 0b3e53a3ddc6 . .. .dockerenv anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var # 想追加一个命令-l,ls -al [root@xizou dockerfile]# docker run 0b3e53a3ddc6 -l docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown. # cmd的清理下 -l 替换了CMD ["ls" ,"-a" ]命令,-l 不是命令,所以报错
测试 ENTRYPOINT 命令
# 1.进入文件 [root@xizou /]# cd /home/dockerfile/ # 2.创建dockerfile [root@xizou dockerfile]# cat dockerfile-entrypoint-test FROM centos:7 ENTRYPOINT ["ls","-a"] # 3.构建镜像 [root@xizou dockerfile]# docker build -f dockerfile-entrypoint-test -t entrypointtest . Sending build context to Docker daemon 4.096kB Step 1/2 : FROM centos:7 ---> eeb6ee3f44bd Step 2/2 : ENTRYPOINT ["ls","-a"] ---> Running in 6ebfea05232f Removing intermediate container 6ebfea05232f ---> 16b996a429de Successfully built 16b996a429de Successfully tagged entrypointtest:latest # 4.运行,发现 ls -a 命令生效 [root@xizou dockerfile]# docker run 16b996a429de . .. .dockerenv anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var # 想追加一个命令-l,ls -al,entrypoint没有替换命令,命令是拼接在后面 [root@xizou dockerfile]# docker run 16b996a429de -l total 64 drwxr-xr-x 1 root root 4096 Oct 30 14:21 . drwxr-xr-x 1 root root 4096 Oct 30 14:21 .. -rwxr-xr-x 1 root root 0 Oct 30 14:21 .dockerenv -rw-r--r-- 1 root root 12114 Nov 13 2020 anaconda-post.log lrwxrwxrwx 1 root root 7 Nov 13 2020 bin -> usr/bin drwxr-xr-x 5 root root 340 Oct 30 14:21 dev drwxr-xr-x 1 root root 4096 Oct 30 14:21 etc drwxr-xr-x 2 root root 4096 Apr 11 2018 home lrwxrwxrwx 1 root root 7 Nov 13 2020 lib -> usr/lib lrwxrwxrwx 1 root root 9 Nov 13 2020 lib64 -> usr/lib64 drwxr-xr-x 2 root root 4096 Apr 11 2018 media drwxr-xr-x 2 root root 4096 Apr 11 2018 mnt drwxr-xr-x 2 root root 4096 Apr 11 2018 opt dr-xr-xr-x 99 root root 0 Oct 30 14:21 proc dr-xr-x--- 2 root root 4096 Nov 13 2020 root drwxr-xr-x 11 root root 4096 Nov 13 2020 run lrwxrwxrwx 1 root root 8 Nov 13 2020 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Apr 11 2018 srv dr-xr-xr-x 13 root root 0 Oct 30 09:23 sys drwxrwxrwt 7 root root 4096 Nov 13 2020 tmp drwxr-xr-x 13 root root 4096 Nov 13 2020 usr drwxr-xr-x 18 root root 4096 Nov 13 2020 var
创建自己的Tomcat镜像
1、准备镜像文件 tomcat压缩包和jdk压缩包
本教程使用的是 apache-tomcat-9.0.68.tar.gz
和 jdk-8u161-linux-x64.tar.gz
。需要自己本地下载,然后上传到服务器。
2、编写Dockerfile文件
FROM centos:7 MAINTAINER xizou<xiongbinzou@163 .com>COPY readme.txt /usr/local /readme.txt ADD jdk-8u161-linux-x64.tar.gz /usr/local / ADD apache-tomcat-9.0.68.tar.gz /usr/local / RUN yum -y install vim ENV MYPATH /usr/localWORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0 _161ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarENV CATALINA_HOME /usr/local/apache-tomcat-9.0 .68 ENV CATALINA_BASH /usr/local/apache-tomcat-9.0 .68 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/binEXPOSE 8080 CMD /usr/local /apache-tomcat-9.0.68/bin/startup.sh && tail -F /usr/local /apache-tomcat-9.0.68/bin/logs/catalina.out
3、构建镜像
[root@xizou tomcat]# docker build -t diytomcat . ...... Successfully built 1a0b96225372 Successfully tagged diytomcat:latest [root@xizou tomcat]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE diytomcat latest 1a0b96225372 About a minute ago 843MB
4、运行容器
# 使用自定义的tomcat镜像构建容器 [root@xizou tomcat]# docker run -d -p 9090:8080 --name xizoutomcat -v /home/xizou/build/tomcat/test:/usr/local/apache-tomcat-9.0.68/webapps/test -v /home/xizou/build/tomcat/logs/:/usr/local/apache-tomcat-9.0.68/logs diytomcat 3a3378620c68d7619622f4914c801bec41686d4f8caabdcdfe97ca867657b40a # 查看当前目录 [root@xizou tomcat]# ls apache-tomcat-9.0.68.tar.gz logs Dockerfile readme.txt jdk-8u161-linux-x64.tar.gz test # 进入容器 [root@xizou tomcat]# docker exec -it 3a3378620c68 /bin/bash # 查看目录 [root@3a3378620c68 local]# ls aegis etc jdk1.8.0_161 libexec share apache-tomcat-9.0.68 games lib readme.txt src bin include lib64 sbin [root@3a3378620c68 local]# cd apache-tomcat-9.0.68/ [root@3a3378620c68 apache-tomcat-9.0.68]# ls BUILDING.txt NOTICE RUNNING.txt lib webapps CONTRIBUTING.md README.md bin logs work LICENSE RELEASE-NOTES conf temp
5、访问测试
[root@xizou /]# curl localhost:9090 # 可以正常访问
6、发布项目(由于做了卷挂载,直接在本地可以发布)
进入test目录,创建WEB-INF目录和index.jsp,进入WEB-INF目录创建web.xml
index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <meta charset="utf-8" > <title>小邹同学(xiongbinzou.github.io)</title> </head> <body> Hello World!<br/> <% System.out.println("---Welcome to my blog---" ); %> </body> </html>
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_4_0.xsd" version ="4.0" > <display-name > Archetype Created Web Application</display-name > </web-app >
打开浏览器,输入 你的服务器ip地址+端口/test/ ,就能看到Hello World!
发布自己的镜像 发布到DockerHub网站
1、在DockerHub网站 注册自己的账号
2、确定账号可以登陆
3、在我们的服务器上提交自己的镜像到DockerHub
[root@xizou tomcat]# docker login --help Usage: docker login [OPTIONS] [SERVER] Log in to a Docker registry. If no server is specified, the default is defined by the daemon. Options: -p, --password string Password --password-stdin Take the password from stdin -u, --username string Username [root@xizou tomcat]# docker login -u xizou1995 Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store
4、登陆完毕后
Login Succeeded # push自己的镜像到服务器上! [root@xizou tomcat]# docker push diytomcat Using default tag: latest The push refers to repository [docker.io/library/diytomcat] 5132fa4d71f7: Preparing 61502ae68a5a: Preparing 09ef56b9dc63: Preparing 6d92c54bcf47: Preparing 174f56854903: Preparing denied: requested access to the resource is denied # 被拒绝 # 修改镜像名为 Dockerhub上你的用户名/镜像名:tag [root@xizou tomcat]# docker tag hello-world xizou1995/hello-world:1.0 [root@xizou tomcat]# docker push xizou1995/hello-world:1.0 The push refers to repository [docker.io/xizou1995/hello-world] e07ee1baac5f: Mounted from library/hello-world 1.0: digest: sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4 size: 525
5、在DockerHub网站你的页面上可以看到
发布到阿里云镜像服务上
1、登陆阿里云
2、找到容器镜像服务
3、找到镜像仓库,如果没有需要自己创建个人实例,在个人实例里能找到镜像仓库
4、在个人实例里创建命名空间
5、创建镜像仓库,选择本地仓库
6、点击仓库名称浏览信息
小结
Docker网络原理 理解Docker0 先清空所有的容器和镜像
docker rm -f $(docker ps -aq) docker rmi -f $(docker images -aq)
测试
三个网络
问题:Docker是如何处理容器网络访问的?比如容器内的tomcat访问容器内的mysql。
[root@xizou /]# docker run -d -P --name tomcat01 tomcat # 查看容器的内部网络地址 ip addr [root@xizou /]# docker exec -it tomcat ip addr # 如果执行失败,进入容器内部安装工具 apt update && apt -y install iproute2,然后再退出容器 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 valid_lft forever preferred_lft forever 4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever # 容器启动时会得到一个 eth0@if5 ip地址,docker分配的 [root@xizou /]# 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.058 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.044 ms 64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.046 ms 64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.055 ms # linux可以ping通docker容器内部
原理
1、每启动一个docker容器,docker就会给docker容器分配一个ip,只要安装了docker,就会有一个网卡docker0桥接技术,使用的是evth-pair技术
[root@xizou /]# 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 valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:16:3e:06:ad:10 brd ff:ff:ff:ff:ff:ff inet 172.20.179.171/20 brd 172.20.191.255 scope global dynamic eth0 valid_lft 315327838sec preferred_lft 315327838sec inet6 fe80::216:3eff:fe06:ad10/64 scope link valid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:46:b8:0a:f8 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:46ff:feb8:af8/64 scope link valid_lft forever preferred_lft forever 5: veth33d487b@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 36:f0:95:72:d4:2b brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::34f0:95ff:fe72:d42b/64 scope link valid_lft forever preferred_lft forever
ip地址多了一个5: veth33d487b@if4
,是为容器内网卡对应的网卡。
发现容器带来的网卡都是成对出现的,一个在容器内部,一个在宿主机,evth-pair技术充当一个桥梁,让宿主机可以与容器内部通信。
按照相同的方式创建tomcat02容器,然后让tomcat01容器ping tomcat02容器,可以发现能够ping通。
tomcat01与tomcat02容器网络通过宿主机内的docker0连接。
所有的容器在不指定网络的情况下,都是docker0路由的,docker会给容器分配一个默认的可用IP。
结论
Docker通过宿主机的Docker0进行桥接,Docker中所有的网络接口都是虚拟的,转发效率高。只要容器删除,虚拟网卡也会消失。
–link 编写一个微服务,database url=ip,项目不启动,数据库ip换掉了,可以通过名字来访问容器,实现高可用。
[root@xizou /]# docker exec -it tomcat02 ping tomcat01 ping: tomcat01: Name or service not known # 如何解决? [root@xizou /]# docker run -d -P --name tomcat03 --link tomcat02 tomcat 6a603a98a0de2fbe2504b01bfb2b40cab602feffcc9d379c5887f2364e6ff5df # 此时tomcat3可以ping通tomcat02 [root@xizou /]# docker exec -it tomcat03 ping tomcat02 # 如果提示ping命令不存在,请执行 docker exec -it tomcat03 apt-get update docker exec -it tomcat03 apt install iputils-ping # tomcat02能够ping同tomcat03吗? 不能 [root@xizou /]# docker exec -it tomcat02 ping tomcat03 ping: tomcat03: Name or service not known [root@xizou /]# docker network ls NETWORK ID NAME DRIVER SCOPE 8e9b37aaa9ce bridge bridge local 0673ec2aaa1c host host local 9ba9f05fc241 none null local [root@xizou /]# docker network inspect 8e9b37aaa9ce [ { "Name": "bridge", "Id": "8e9b37aaa9ce5bb9d88f68daa4f3eea16d1c8cbfe62a127a7e019ef931687391", "Created": "2022-10-31T01:31:03.542724354+08:00", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "3b8af7fbc37fd2905b411a9e0a3b4bbc57c2685a555aea6482ac7948858a01aa": { "Name": "tomcat01", "EndpointID": "db565d8188ff9fd69be16c86d193199eed1934b9ae416cdf903a12755b20fbe4", "MacAddress": "02:42:ac:11:00:02", "IPv4Address": "172.17.0.2/16", "IPv6Address": "" }, "6a603a98a0de2fbe2504b01bfb2b40cab602feffcc9d379c5887f2364e6ff5df": { "Name": "tomcat03", "EndpointID": "40fb946ba46cba96573646ed6374272b1c27c490c1a1c7f14b084ddb9296f1c3", "MacAddress": "02:42:ac:11:00:04", "IPv4Address": "172.17.0.4/16", "IPv6Address": "" }, "92a91f9faa29e067d006ace0b4a1c32245b4521ab71098db1503c78f023e45c6": { "Name": "tomcat02", "EndpointID": "a0a96ea13aaef24383be2abd638422cfb59cfda4e670ec2a392418d7f96d4c5e", "MacAddress": "02:42:ac:11:00:03", "IPv4Address": "172.17.0.3/16", "IPv6Address": "" } }, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" }, "Labels": {} } ]
[root@xizou /]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6a603a98a0de tomcat "catalina.sh run" 6 minutes ago Up 6 minutes 0.0.0.0:49155->8080/tcp, :::49155->8080/tcp tomcat03 92a91f9faa29 tomcat "catalina.sh run" 41 minutes ago Up 41 minutes 0.0.0.0:49154->8080/tcp, :::49154->8080/tcp tomcat02 3b8af7fbc37f tomcat "catalina.sh run" About an hour ago Up About an hour 0.0.0.0:49153->8080/tcp, :::49153->8080/tcp tomcat01 [root@xizou /]# docker inspect tomcat03 # 在HostConfig的Links字段里能看到link到tomcat02,如: "Links": ["/tomcat02:/tomcat03/tomcat02"], # 也可以查看/etc/hosts文件 [root@xizou /]# docker exec -it tomcat03 cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.3 tomcat02 92a91f9faa29 172.17.0.4 6a603a98a0de
本质:–link 就是在容器tomcat03的hosts配置在中增加了一个tomcat02的映射
不建议使用–link实现网络映射
自定义网络 查看所有的docker网络
[root@xizou /]# docker network ls NETWORK ID NAME DRIVER SCOPE 8e9b37aaa9ce bridge bridge local 0673ec2aaa1c host host local 9ba9f05fc241 none null local [root@xizou /]# docker network --help Usage: docker network COMMAND Manage networks Commands: connect Connect a container to a network create Create a network disconnect Disconnect a container from a network inspect Display detailed information on one or more networks ls List networks prune Remove all unused networks rm Remove one or more networks Run 'docker network COMMAND --help' for more information on a command.
网络模式
bridge:桥接 docker(默认)
none:不配置网络
host:和宿主机共享网络
container:容器网络连通(不常用)
# 直接启动命令 --net bridge,这个就是docker0 docker run -d -P --name tomcat01 tomcat 等价于 docker run -d -P --name tomcat01 --net bridge tomcat # docker0的特点:默认,域名不能访问。--link可以打通 # 创建一个自定义网络 # --driver bridge # --subnet 192.168.0.0/16 # --gateway 192.168.0.1 [root@xizou /]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet 8870e01ec415be0a02e181760b6bec5040edb660762903ec3c6dac14ffd368dd [root@xizou /]# docker network ls NETWORK ID NAME DRIVER SCOPE 8e9b37aaa9ce bridge bridge local 0673ec2aaa1c host host local 8870e01ec415 mynet bridge local 9ba9f05fc241 none null local [root@xizou /]# docker network inspect mynet [ { "Name": "mynet", "Id": "8870e01ec415be0a02e181760b6bec5040edb660762903ec3c6dac14ffd368dd", "Created": "2022-10-31T11:31:39.986065834+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": {}, "Options": {}, "Labels": {} } ] # 使用自定义网络 [root@xizou /]# docker run -d -P --name tomcat01 --net mynet tomcat 5a311d6ef0e2fdd71afc8595de172cd54f7b51cb500f7040aebf562efea4896f [root@xizou /]# docker run -d -P --name tomcat02 --net mynet tomcat 5459203e0fb8dcf80a79d24ad6dbf07765b0d8103f879c03aef3e20ec806a4a6 [root@xizou /]# docker network inspect mynet [ { "Name": "mynet", "Id": "8870e01ec415be0a02e181760b6bec5040edb660762903ec3c6dac14ffd368dd", "Created": "2022-10-31T11:31:39.986065834+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": { "5459203e0fb8dcf80a79d24ad6dbf07765b0d8103f879c03aef3e20ec806a4a6": { "Name": "tomcat02", "EndpointID": "ee8fe045e89d3c7c20ee1ea48f1f6fbb6877967fa67e8ccaa69bab2b9ed29694", "MacAddress": "02:42:c0:a8:00:03", "IPv4Address": "192.168.0.3/16", "IPv6Address": "" }, "5a311d6ef0e2fdd71afc8595de172cd54f7b51cb500f7040aebf562efea4896f": { "Name": "tomcat01", "EndpointID": "30d69fc865bc8020da370fd3a0e810e2f7a4e51f7ecc80a88c8bc1bfe66ce541", "MacAddress": "02:42:c0:a8:00:02", "IPv4Address": "192.168.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] # 再次测试ping连接,使用ip和使用容器名都可以ping成功 [root@xizou ~]# docker exec -it tomcat01 ping tomcat02 PING tomcat02 (192.168.0.3) 56(84) bytes of data. 64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.047 ms 64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.062 ms 64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.042 ms
自定义网络的docker都已经维护好了对应的关系,推荐平时使用这样的网络
好处:不同的集群使用不同的网络,保证集群是安全和健康的。
网络连通
[root@xizou ~]# docker network connect --help Usage: docker network connect [OPTIONS] NETWORK CONTAINER Connect a container to a network Options: --alias strings Add network-scoped alias for the container --driver-opt strings driver options for the network --ip string IPv4 address (e.g., 172.30.100.104) --ip6 string IPv6 address (e.g., 2001:db8::33) --link list Add link to another container --link-local-ip strings Add a link-local address for the container
让使用Docker0作为桥接的容器和使用自定义网络mynet作为桥接的容器连通。
假设:
使用Docker0作为桥接的容器有:tomcat01、tomcat02
使用自定义网络mynet作为桥接的容器有:tomcat-net-01、tomcat-net-02
[root@xizou /]# docker network connect mynet tomcat01 [root@xizou /]# docker network inspect mynet 可以发现Containes字段里多了tomcat01 [root@xizou /]# docker exec -it tomcat01 ping tomcat-net-01
实战:Redis集群
# 创建网卡 docker network create redis --subnet 172.38.0.0/16 # 通过脚本创建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 done # 启动docker docker run -p 6371:6379 -p 16371:16739 --name redis-1 -v /mydate/redis/node-1/data:/data -v /mydate/redis/node-1/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6372:6379 -p 16372:16739 --name redis-2 -v /mydate/redis/node-2/data:/data -v /mydate/redis/node-2/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6373:6379 -p 16373:16739 --name redis-3 -v /mydate/redis/node-3/data:/data -v /mydate/redis/node-3/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6374:6379 -p 16374:16739 --name redis-4 -v /mydate/redis/node-4/data:/data -v /mydate/redis/node-4/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6375:6379 -p 16375:16739 --name redis-5 -v /mydate/redis/node-5/data:/data -v /mydate/redis/node-5/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf docker run -p 6376:6379 -p 16376:16739 --name redis-6 -v /mydate/redis/node-6data:/data -v /mydate/redis/node-6/conf/redis.conf:/etc/redis/redis.conf -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf # 进入任一个容器内 docker exec -it redis-1 /bin/sh # 创建集群 /data # 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 /data # redis-cli -c 127.0.0.1:6379> cluster info 观察发现已经创建了6个redis服务,其中3个主机,3个从机,主机的数据会同步到对应的从机,主机挂掉后,从机会替代挂掉的主机工作
实战:SpringBoot微服务打包成Docker镜像 步骤:
1、构建SpringBoot项目
2、打包应用
3、编写Dockerfile
FROM java:8 MAINTAINER xizou<xiongbinzou@163 .com>COPY *.jar /app.jar CMD ["--server.port=8080" ] EXPOSE 8080 ENTRYPOINT ["java" , "-jar" , "/app.jar" ]
4、构建镜像
docker build -t helloworld . docker images docker run -d -P --name helloworld-web helloword curl localhost:32779
5、发布运行
扩展 什么是容器编排 问题 :将应用程序打包到了Docker容器中后,如何在生产环境中运行它,如果应用程序有依赖于其他容器,如数据库、消息服务或其他后端服务容器,该怎么办?如果用户数量增加并且你需要扩展你的应用程序怎么办?如果要缩小规模减少负载该怎么做?
思考 :需要有一个具有一组资源和功能的底层平台,这个平台能够统筹容器之间的连接,并且根据负载可自动扩展或缩减容器。
方案 :这种自动部署和管理容器的整个过程称为容器编排 ,Docker有自己的容器编排工具,叫做Docker Swarm,但是缺少复杂应用程序所需的一些高级功能,MESOS也是一种容器编排技术,虽然支持许多高级功能,但是很难设置和上手。Kubernets是一种容器编排技术,设置和入门有点困难,提供了许多自定义部署的选项和支持复杂架构的部署,目前所有的公有云服务供应商都支持了Kubernetes。
容器编排 的优势:
应用程序高可用 。硬件故障不会导致应用程序停机,因为容器编排技术使我们在不同节点上运行了应用程序的多个实例。用户流量在容器间负载均衡 。需求增加时,可轻松、快速部署更多应用程序实例 。
Kubernetes是一种容器编排技术,用于编排数百个应用程序的部署和管理。
Kubernetes架构 在设置Kubernetes集群前,先介绍一些Kubernetes的术语。
节点Nodes :节点是安装了Kubernetes的物理或虚拟机器,节点是工作机器,是Kubernetes将容器启动的地方。过去也叫Minions。
集群Cluster :集群是一组组合在一起的节点,即使一个节点发生故障,依然可以从其他节点访问你的应用程序,此外节点也有助于分担负载,
Master :Master是另一个安装了Kubernetes的节点,被配置为Master,负责监视集群中的节点并负责工作节点上容器的编排,存储着集群成员的信息。当一个节点发生故障时,Master负责将节点的工作负载转移到另一个工作节点。
Kubernetes :在系统上安装Kubernetes时,实际上是在安装以下组件
API Server :充当Kubernetes的前端,包括用户、管理设备、命令行界面、从API服务器到Kubernets集群。etcd :是Kubernetes使用可靠键值来存储用于管理集群的所有数据,当集群中有多个节点和多个Master时,etcd会以分布式的方式在集群的所有节点上存储着所有这些信息。etcd负责在集群内实现锁,以确保Master之间不存在冲突。Scheduler :负责跨多个节点分发工作或容器,它查找新创建的容器并将它们分配给节点。Controller :是编排背后的大脑,它负责在节点、容器或端点出现故障时进行统通知和响应,负责决定在这种情况下启动新容器。Container Runtime :是运行容器的底层软件,如Docker。Kubelet :是在集群中每个节点上运行的代理,负责保证容器按预期在节点上运行。Pod :Kubernetes不直接在工作节点上部署容器,容器封装进而成为Pod的Kubernetes对象,Pod是应用程序的单个实例,Pod是你可以在Kubernetes创建的最小对象。
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个)容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的内容总是并置(colocated)的并且一同调度,在共享的上下文中运行。
POD定义文件:
appVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nigix-container image: nginx
Replica Set :ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。ReplicaSet 是通过一组字段来定义的,包括一个用来识别可获得的 Pod 的集合的选择算符、一个用来标明应该维护的副本个数的数值、一个用来指定应该创建新 Pod 以满足副本个数条件时要使用的 Pod 模板等等。 每个 ReplicaSet 都通过根据需要创建和删除 Pod 以使得副本个数达到期望值, 进而实现其存在价值。当 ReplicaSet 需要创建新的 Pod 时,会使用所提供的 Pod 模板。
ReplicaSet 定义文件:
apiVersion: apps/v1 kind: ReplicaSet metadata: name: myapp-replicaset labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp type: front-end spec: containers: - name: nginx-container image: nginx replicas: 3 selector: matchLabels: type: front-end
Deployment :Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,我们建议使用 Deployment 而不是直接使用 ReplicaSet, 除非你需要自定义更新业务流程或根本不需要更新。
你负责描述 Deployment 中的目标状态,而 Deployment控制器(Controller)以受控速率更改实际状态, 使其变为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 更新其资源。
应用:
1.当你有一个需要部署在生产环境中的Web服务器,你需要运行的不是一个而是多个Web服务器实例
2.每当应用程序需要更新版本时,你需要无缝升级Docker实例,但是当你升级实例时,不希望一次升级所有实例,因为会影响正在访问你应用程序的用户,因此你希望一个接一个升级他们,这种升级称为滚动更新。
3.当你执行的升级之一导致了意外错误,并且你被要求撤销最近的更改,你希望能够回滚最近执行的更改。
4.当对环境进行多项更改,例如升级底层Web服务器版本以及扩展你的环境并修改资源等,你不想在命令运行后立即应用每个更改,而是希望暂停应用进行更改,然后恢复,以便一起推出所有更改。
Deployment定义文件:
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment labels: app: myapp type: front-end spec: template: metadata: name: myapp-pod labels: app: myapp spec: containers: - name: nginx-container image: nginx replicas: 3 selector: matchLabels: type: front-end
POD、Replica Set、Deployment关系
工作节点拥有Container Runtime、Kubelet
Master节点拥有API Server、etcd、Controller、Scheduler
Kubernetes网络设置
IP地址指定给POD:
Kubernetes网络需求:
Pod 能够与所有其他节点上的 Pod 通信, 且不需要网络地址转译(NAT) 节点上的代理(比如:系统守护进程、kubelet)可以和节点上的所有 Pod 通信 Kubernetes服务类型
apiVersion: v1 kind: Service metadata: name: myapp-service spec: type: NodePort ports: - targetPort: 80 port: 80 nodePort: 30008 selector: app: myapp type: front-end
外部执行指令http://192.168.1.2:30008即可以访问节点里POD应用
为每种应用服务创建一个单独的Service,这个Service可定义提供相同应当服务节点的网络地址、端口配置。
apiVersion: v1 kind: Service metadata: name: back-end spec: type: ClusterIP ports: - targetPort: 80 port: 80 selector: app: myapp type: back-end
apiVersion: v1 kind: Service metadata: name: myapp-service spec: type: LoadBalancer ports: - targetPort: 80 port: 80 nodePort: 30008
kubectl工具 kubectl工具在Kubernetes集群上部署和管理应用程序,获取集群信息,获取集群中其他节点的状态并管理许多其他事情。
kubectl run hello-minikube # 在集群上部署应用程序 kubectl cluster-info # 查看集群信息 kubectl get nodes # 用于列出集群的所有节点部分
可以通过Minicube 项目体验kubernetes的部署与应用。
实战:Kubernetes部署投票应用
解释:
voting-app: 前端页面,用户通过该页面进行投票,python
redis:数据库,用户的投票数据暂存在内存的redis里,redis
worker:从redis里读取用户投票数据,统计计算后存入持久性数据库,.Net
postgress:数据库,持久化存储用户的投票数据跟统计结果,postgress
result-app: 前端页面,显示投票统计数据,Javascript
部署的目标
1、运行容器
2、容器间的连通
3、外部访问
解决方案1 (不使用Deployment,不建议):
voting-app-pod.yaml
apiVersion: v1 kind: Pod metadata: name: voting-app-pod labels: name: voting-app-pod app: demo-voting-app spec: containers: - name: voting-app image: kodekcloud/examplevotingapp_vote:v1 ports: - containerPort: 80
result-app-pod.yaml
apiVersion: v1 kind: Pod metadata: name: result-app-pod labels: name: result-app-pod app: demo-voting-app spec: containers: - name: result-app image: kodekcloud/examplevotingapp_result:v1 ports: - containerPort: 80
redis-pod.yaml
apiVersion: v1 kind: Pod metadata: name: redis-pod labels: name: redis-pod app: demo-voting-app spec: containers: - name: redis image: redis ports: - containerPort: 6379
postgres-pod.yaml
apiVersion: v1 kind: Pod metadata: name: postgres-pod labels: name: postgres-pod app: demo-voting-app spec: containers: - name: postgres image: postgres ports: - containerPort: 5432 env: - name: POSTGRES_USER value: "postgres" - name: POSTGRES_PASSWORD value: "postgres"
worker-app-pod.yaml
apiVersion: v1 kind: Pod metadata: name: worker-app-pod labels: name: worker-app-pod app: demo-voting-app spec: containers: - name: worker-app image: kodekcloud/examplevotingapp_worker:v1
redis-service.yaml
apiVersion: v1 kind: Service metadata: name: redis labels: name: redis-service app: demo-voting-app spec: ports: - port: 6379 targetPort: 6379 selector: name: redis-pod app: demo-voting-app
postgres-service.yaml
apiVersion: v1 kind: Service metadata: name: db labels: name: postgres-service app: demo-voting-app spec: ports: - port: 5432 targetPort: 5432 selector: name: postgres-pod app: demo-voting-app
voting-app-service.yaml
apiVersion: v1 kind: Service metadata: name: voting-service labels: name: voting-service app: demo-voting-app spec: type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30004 selector: name: voting-app-pod app: demo-voting-app
result-app-service.yaml
apiVersion: v1 kind: Service metadata: name: result-service labels: name: result-service app: demo-voting-app spec: type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30005 selector: name: result-app-pod app: demo-voting-app
将上面所有文件放入voting-app文件夹下
cd voting-app kubectl get pods,svc kuberctl create -f voting-app-pod.yaml kuberctl create -f voting-app-service.yaml # 查看投票服务的url minikube service voting-service --url kuberctl create -f redis-pod.yaml kuberctl create -f redis-service.yaml kubectl get pods,svc kuberctl create -f postgres-pod.yaml kuberctl create -f postgres-service.yaml kubectl get pods,svc kuberctl create -f worker-app-pod.yaml kubectl get pods,svc kuberctl create -f result-app-pod.yaml kuberctl create -f result-app-service.yaml kubectl get pods,svc # 查看投票结果服务的url minikube service voting-service --url
解决方案2 (使用Deployment)
voting-app-deployment.yaml
apiVersion: v1 kind: Deployment metadata: name: voting-app-deployment labels: name: voting-app-deployment app: demo-voting-app spec: replicas: 1 template: metadata: name: voting-app-pod labels: name: voting-app-pod app: demo-voting-app spec: containers: - name: voting-app image: kodekcloud/examplevotingapp_vote:v1 ports: - containerPort: 80 selector: matchLabels: name: voting-app-pod app: demo-voting-app
redis-deployment.yaml
apiVersion: v1 kind: Deployment metadata: name: redis-deployment labels: name: redis-deployment app: demo-voting-app spec: replicas: 1 template: metadata: name: postgres-pod labels: name: postgres-pod app: demo-voting-app spec: containers: - name: postgres image: postgres ports: - containerPort: 5432 env: - name: POSTGRES_USER value: "postgres" - name: POSTGRES_PASSWORD value: "postgres" selector: matchLabels: name: redis-pod app: demo-voting-app
postgress-deployment.yaml
apiVersion: v1 kind: Deployment metadata: name: postgres-deployment labels: name: postgres-deployment app: demo-voting-app spec: replicas: 1 template: metadata: name: redis-pod labels: name: redis-pod app: demo-voting-app spec: containers: - name: redis image: redis ports: - containerPort: 6379 selector: matchLabels: name: postgres-pod app: demo-voting-app
worker-deployment.yaml
apiVersion: v1 kind: Deployment metadata: name: worker-app-deployment labels: name: worker-app-deployment app: demo-voting-app spec: replicas: 1 template: metadata: name: worker-app-pod labels: name: worker-app-pod app: demo-voting-app spec: containers: - name: worker-app image: kodekcloud/examplevotingapp_worker:v1 selector: matchLabels: name: worker-app-pod app: demo-voting-app
result-app-deployment.yaml
apiVersion: v1 kind: Deployment metadata: name: result-app-deployment labels: name: result-app-deployment app: demo-voting-app spec: replicas: 1 template: metadata: name: voting-app-pod labels: name: voting-app-pod app: demo-voting-app spec: containers: - name: voting-app image: kodekcloud/examplevotingapp_result:v1 ports: - containerPort: 80 selector: matchLabels: name: result-app-pod app: demo-voting-app
确保所有文件放入voting-app文件夹下,包括方案1的文件
cd voting-app kubectl get pods,svc kuberctl create -f voting-app-deployment.yaml kuberctl create -f voting-app-service.yaml # 查看投票服务的url minikube service voting-service --url kuberctl create -f redis-deployment.yaml kuberctl create -f redis-service.yaml kubectl get deployments kuberctl create -f postgres-deployment.yaml kuberctl create -f postgres-service.yaml kubectl get deployments kuberctl create -f worker-app-deployment.yaml kubectl get deployments kuberctl create -f result-app-deployment.yaml kuberctl create -f result-app-service.yaml kubectl get deployments,svc # 查看投票结果服务的url minikube service voting-service --url # 修改投票和结果服务的集群为3 kubectl scale deployment voting-app-deployment --replicas=3 kubectl scale deployment result-app-deployment --replicas=3
为什么Podman比Docker更安全 Docker必须由root用户启动一个守护进程才能使用systemctl start docker
,其次,普通用户需要加入容器组,才能够运行和启动Docker,如此会存在一些安全问题,如普通用户可以通过容器进行提权。
# 查看docker版本 [root@xizou /]# docker --version Docker version 20.10.21, build baeda1f # root用户启动docker服务进程 [root@xizou /]# systemctl start docker # 查看docker服务状态 [root@xizou /]# systemctl status docker ● docker.service - Docker Application Container Engine Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) Active: active (running) since Wed 2022-11-02 12:24:26 CST; 47s ago Docs: https://docs.docker.com Main PID: 31905 (dockerd) Tasks: 7 Memory: 27.9M CGroup: /system.slice/docker.service └─31905 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.199751948+08:00" level=info m...ing" Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.431287299+08:00" level=info m...ing" Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.475634500+08:00" level=info m...ing" Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.676136067+08:00" level=info m...ess" Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.778914793+08:00" level=info m...ing" Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.891111549+08:00" level=info m...ne." Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.907790255+08:00" level=info m...0.21 Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.907847502+08:00" level=info m...ion" Nov 02 12:24:26 xizou systemd[1]: Started Docker Application Container Engine. Nov 02 12:24:26 xizou dockerd[31905]: time="2022-11-02T12:24:26.924507836+08:00" level=info m...ock" Hint: Some lines were ellipsized, use -l to show in full. # 查看当前所有镜像 [root@xizou /]# docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE # 下载镜像 [root@xizou /]# docker pull centos Using default tag: latest latest: Pulling from library/centos a1d0c7532777: Pull complete Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177 Status: Downloaded newer image for centos:latest docker.io/library/centos:latest [root@xizou /]# docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 5d0da3dc9764 13 months ago 231MB # 创建并切换用户 [root@xizou /]# adduser test -G docker [root@xizou /]# su - test # 普通用户能看到root用户下载的镜像,如果使用podman则不会显示 [test@xizou ~]$ docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 5d0da3dc9764 13 months ago 231MB # 普通用户运行centos应用的容器,挂载根目录到容器内的/host目录,并把容器内的/host目录作为容器的根目录 [test@xizou ~]$ docker run -it --privileged -v /:/host centos chroot /host sh-4.2# # 容器内能够执行命令获取原本普通用户没有权限的内容 sh-4.2# head -1 /etc/shadow root:$6$8Ufh0Fb6$tpjmUtcq0r36xLc.q9tDb.5/ECL5cS6iOmglyETI23.C0BbGO0uHLtS7c97O6YvKV.CBQvufaP7mHJ25P.J6X/:19293:0:99999:7::: sh-4.2# exit exit [test@xizou ~]$ head -1 /etc/shadow head: cannot open ‘/etc/shadow’ for reading: Permission denied [test@xizou ~]$ exit logout [root@xizou /]# head -1 /etc/shadow root:$6$8Ufh0Fb6$tpjmUtcq0r36xLc.q9tDb.5/ECL5cS6iOmglyETI23.C0BbGO0uHLtS7c97O6YvKV.CBQvufaP7mHJ25P.J6X/:19293:0:99999:7:::
上面例子举证了Docker造成的安全隐患,通过挂载数据卷的方式,普通用户能够在容器内获得root权限,能够随意更改文件。另外,容器内创建的用户,退出容器后居然存在于宿主机中。容器的隔离性被破坏。
# 解决方案: 方案1. 使用podman替代docker alias docker=podman 方案2. 限制只有root用户才能使用docker 将docker.sock文件的属组改成root组 [root@xizou /]# cd /var/run/ [root@xizou run]# chown root:root docker.sock
后续学习方向 IDEA整合Docker Docker Compose、yaml Docker Swarm、Kubernetes CI/CD Jenkins 参考文章 本文是笔者通过下列视频教程和文档进行Docker进阶学习的记录,有部分修改和补充,转载请注明出处,并附带下面链接。
1.【B站up主-遇见狂神说】
2.【kubernetes官网】
3.【Udemy学院-Kubernetes初学者教程视频】