Docker基础
Docker是什么 Docker 是一个开源的容器化平台,用于开发、交付和运行应用程序。 如图所示,简单来说,docker是一艘运载着许多相互隔离、互相独立的集装箱,每个箱子内部运行着独立的程序。
为什么使用Docker Develop faster. Run anywhere,这是docker官网上的docker原话,更快的开发,到处运行。
1、解决传统环境差异导致的兼容性问题
按照传统开发模式,一个产品有2套部署环境:本地开发,线上环境,存在大量的运维部署问题和环境差异,费事费力。最典型的问题是开发人员——我本地明明跑起来正常的,为什么线上不行
2、快速部署、快速迭代的兴起
Devops的快速发展,传统的开发模式时,开发人员提供jar包,然后手动上传服务器,然后java -jar启动新的包,有时遇到,依赖的其他组件升级,那就更是麻烦,比如mysql、redis、xxljob等,涉及到了环境依赖、先后问题,运维难度极大。有了docker,结合Jenkins、可以快速实现持续开发、持续部署、编排容器。
3、容器编排技术的兴起
通过容器编排工具和 Docker 的结合,可以轻松地实现复杂的应用架构,如微服务架构,多个微服务可以分别打包成 Docker 容器,通过容器编排工具进行统一管理和调度
4、资源利用和成本优化
Docker 容器相比于传统的虚拟机,具有更轻量级的特点。虚拟机需要为每个实例运行一个完整的操作系统,而 Docker 容器共享主机操作系统内核,多个容器可以在同一主机上运行,大大减少了系统资源的占用。这使得在相同的硬件资源下,可以部署更多的应用,提高了资源利用率,降低了企业的硬件采购和运维成本。
Docker和虚拟机的区别 docker出现之前,虚拟技术主流就是虚拟机,对应的软件有Vmvare,VirtualBox等。
总的来说,docker不像虚拟机那么重,容器共用宿主机的操作系统,每个容器只需要包含自身需要的环境和程序,所以比较小 ,启动也快 ,资源利用率更高
应用更快速的交付和部署 传统:一堆帮助文档,安装程序 Docker:打包镜像发布测试,一键运行
更便捷的升级和扩缩容 使用了Docker之后,我们部署应用就和搭积木一样! 项目打包为一个镜像,扩展服务器A!服务器B
更简单的系统运维 在容器化之后,我们的开发,测试环境都是高度一致的。
更高效的计算资源利用: Docker是内核级别的虚拟化,可以再一个物理机上可以运行很多的容器实例!服务器的性能可以被压榨到极致。
Docker怎么用 docker核心概念 镜像(image) Docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像 => run => tomcat01容器, 通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)
容器(container) Docker利用容器技术,独立运行一个或者一组应用, 通过镜像来创建的。可以理解为容器是镜像的实例
容器可以启动,停止,删除等
仓库(repository) 存放镜像的地方,Docker Hub(默认是国外的),各大厂商也有自己的docker镜像仓库
docker底层原理 docker如何工作 Docker是一个Client-Server结构的服务器,Docker的守护进程运行在主机上,通过Socket从客户端访问!Docker-Server接收到Docker-Client指令,就会执行这个命令
docker为什么比VM快 1、Docker有着比虚拟机更少的抽象层 2、docker利用的是宿主机的内核,vm需要是Guest os
所以说,新建一个容器的时候,docker不需要想虚拟机一样重新加载一个操作系统内核,避免引导。虚拟机是加载 GuestOS,分钟级别的,而docker是利用宿主机的操作系统吗,省略了这个复杂的过程,秒级!
docker安装及镜像仓库配置 参考上篇
Docker常用命令
帮助命令: 1 2 3 docker version #查看docker版本信息 docker info #显示docker系统信息,包括镜像和容器的数量 docker --help #帮助命令
镜像命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 docker images 查看所有本地主机上的镜像 -a:列出本地所有镜像 -q:只列出镜像ID –digests:显示镜像的摘要信息 –no trunc:显示完整的镜像信息 -s:列出收藏数不小于指定值的镜像 docker search 查找镜像 docker pull 镜像名[:tag] 下拉镜像 如果不写tag,默认就是latest docker rmi 删除镜像 docker rmi $(docker images -aq) # 删除所有镜像
容器命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 docker run [可选参数] image #运行镜像 # 参数说明 --name=“Name” 容器名字 tomcat01 tomcat02 用来区分容器 -d 后台方式运行 -it 使用交互方式运行,进入容器查看内容 -p 指定容器的端口 -p 8080 :8080 -p ip:主机端口:容器端口 -p 主机端口:容器端口(常用) -p 容器端口 容器端口 -p 随机指定端口 # 测试,启动并进入容器 [root@iZ2zeg4ytp0whqtmxbsqiiZ ~]# docker run -it centos /bin/bash [root@74 e82b7980e7 /]# ls # 查看容器内的centos,基础版本,很多命令是不完善的 bin etc lib lost+found mnt proc run srv tmp var dev home lib64 media opt root sbin sys usr # 从容器中退回主机 [root@77969 f5dcbf9 /]# exit exit 列出所有的运行的容器 # docker ps #列出本地运行的容器 # 列出当前正在运行的容器 -a # 列出正在运行的容器包括历史容器 -n=? # 显示最近创建的容器 -q # 只显示当前容器的编号 退出容器exit # 直接退出容器并关闭 Ctrl + P + Q # 容器不关闭退出 删除容器 docker rm -f 容器id # 删除指定容器 docker rm -f $(docker ps -aq) # 删除所有容器 docker ps -a -q|xargs docker rm -f # 删除所有的容器 启动和停止容器的操作 docker start 容器id # 启动容器 docker restart 容器id # 重启容器 docker stop 容器id # 停止当前正在运行的容器 docker kill 容器id # 强制停止当前的容器 显示日志 docker logs -tf --tail number 容器id -tf # 显示日志 --tail number # 显示日志条数 [root@iZ2zeg4ytp0whqtmxbsqiiZ /]# docker logs -tf --tail 10 a0d580a21251 查看容器中进程信息ps # 命令 docker top 容器id [root@iZ2zeg4ytp0whqtmxbsqiiZ /]# docker top df358bc06b17 查看镜像的元数据 docker inspect 容器id 进入当前正在运行的容器 docker exec -it 容器id /bin/bash docker attach 容器id # docker exec # 进入容器后开启一个新的终端,可以在里面操作 # docker attach # 进入容器正在执行的终端,不会启动新的进程 从容器中拷贝文件到主机 docker cp 容器id:容器内路径 目的地主机路径 #docker cp 7 af535f807e0:/home/Test.java /home 提交容器成为一个新的副本 docker commit docker commit -m="提交的描述信息" -a="作者名" 容器id 目标镜像名:[tag]
Docker部署软件实战 1、安装Nginx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 # 1 . 搜索镜像 search 建议去docker hub搜索,可以看到帮助文档 # 2 . 下载镜像 pull # 3 . 运行测试 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 0 d120b6ccaa8 32 hours ago 215 MB nginx latest 08393 e824c32 7 days ago 132 MB # -d 后台运行 # -name 给容器命名 # -p 宿主机端口:容器内部端口 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# docker run -d --name nginx01 -p 3344 :80 nginx # 后台方式启动启动镜像 fe9dc33a83294b1b240b1ebb0db9cb16bda880737db2c8a5c0a512fc819850e0 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe9dc33a8329 nginx "/docker-entrypoint.…" 4 seconds ago Up 4 seconds 0 .0 .0 .0 :3344 ->80 /tcp nginx01 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# curl localhost:3344 # 本地访问测试 # 进入容器 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# docker exec -it nginx01 /bin/bashroot@fe9dc33a8329:/# whereis nginx nginx : /usr /sbin /nginx /usr /lib /nginx /etc /nginx /usr /share /nginx root @fe9dc33a8329 :/# cd /etc /nginx /root @fe9dc33a8329 :/etc /nginx # ls conf.d koi -utf mime.types nginx.conf uwsgi_params fastcgi_params koi -win modules scgi_params win -utf
2、安装Tomcat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 官方的使用 docker run -it --rm tomcat:9 .0 # 我们之前的启动都是后台的,停止了容器之后, 容器还是可以查到,docker run -it --rm 一般用来测试,用完就删 # 下载再启动 docker pull tomcat # 启动运行 docker run -d -p 3344 :8080 --name tomcat01 tomcat # 测试访问没有问题 # 进入容器 docker exec -it tomcat01 /bin/bash # 发现问题:1 .linux命令少了, 2 . webapps下内容为空 默认是最小的镜像,所有不必要的都剔除了,保证最小可运行环境即可
3、ES+Kibana 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 # es 暴露的端口很多 # es 十分的耗内存 # es 的数据一般需要放置到安全目录! 挂载 # --net somenetwork 网络配置 # 启动elasticsearch docker run -d --name elasticsearch --net somenetwork -p 9200 :9200 -p 9300 :9300 -e "discovery.type =single-node" elasticsearch:7 .6 .2 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# docker run -d --name elasticsearch -p 9200 :9200 -p 9300 :9300 -e "discovery.type =single-node" elasticsearch:7 .6 .2 a920894a940b354d3c867079efada13d96cf9138712c76c8dea58fabd9c7e96f # 启动了linux就卡主了,docker stats 查看cpu状态 # 测试一下es成功了 [root@iZ2zeg4ytp0whqtmxbsqiiZ home]# curl localhost:9200 { "name" : "a920894a940b", "cluster_name" : "docker-cluster", "cluster_uuid" : "bxE1TJMEThKgwmk7Aa3fHQ", "version" : { "number" : "7 .6 .2 ", "build_flavor" : "default", "build_type" : "docker", "build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f", "build_date" : "2020 -03 -26 T06:34 :37 .794943 Z", "build_snapshot" : false, "lucene_version" : "8 .4 .0 ", "minimum_wire_compatibility_version" : "6 .8 .0 ", "minimum_index_compatibility_version" : "6 .0 .0 -beta1" }, "tagline" : "You Know, for Search" } # 增加内存限制,修改配置文件 -e 环境配置修改 docker run -d --name elasticsearch -p 9200 :9200 -p 9300 :9300 -e "discovery.type =single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7 .6 .2
镜像讲解 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含某个软件所需的所有内容,包括代码、库、环境变量和配合文件。
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
UnionFS 文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
分层理解
所有的 Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。举一个简单的例子,假如基于 Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!这一层就是我们通常说的容器层,容器之下的都叫镜像层,当我们对启动后的容器继续做什么操作后打包成镜像,相当于在原镜像层的基础上,再堆叠一层。
容器数据卷 问题:mysql作为容器启动产生数据后,容器重启或者关闭怎么办,数据怎么保存
什么是容器数据卷 容器之间可以有一个数据共享的技术,docker容器中产生的数据,同步到本地
使用数据卷 方式一:直接使用命令来挂载,-v
1 2 docker run -it -v 主机目录:容器目录 [root@localhost ~]# docker run -it -v /home/ceshi:/home centos01:1 .0 /bin/bash
实战:安装MySQL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 获取镜像 # docker pull mysql:5 .7 # 运行容器, 需要做数据挂载! # 安装启动mysql,需要配置密码(注意) # 官方测试, docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag # 启动我们的 -d # 后台运行 -p # 端口隐射 -v # 卷挂载 -e # 环境配置 --name # 容器的名字 # docker run -d -p 3344 :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 # 启动成功之后,我们在本地使用navicat链接测试一下 # navicat链接到服务器的3344 --- 3344 和 容器的3306 映射,这个时候我们就可以连接上mysql喽! # 在本地测试创建一个数据库,查看下我们的路径是否ok!
具名挂载与匿名挂载 1 2 3 4 5 6 7 8 9 10 11 # 如何确定是具名挂载还是匿名挂载,还是指定路径挂载 -v 容器内路径 #匿名挂载 -v 卷名:容器内路径 #具名挂载 -v /宿主机路径:容器内路径 #指定路径挂载 # 通过 -v 容器内路径:ro rw 改变读写权限 ro(只读) rw(可读可写) # 一旦设置了容器权限,容器对我们挂载出来额内容就有限定了 [root@localhost home]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx [root@localhost home]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx # ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作的
所有docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxxx/_data我们通过具名挂载可以方便的找到我们的一个卷,大多数情况下使用的是具名挂载
多个mysql同步数据 1 2 3 4 5 [root@localhost /]# docker run -it --name docker01 syw/centos:1 .0 [root@9998 f8ab8c5a /]# ls bin etc lib lost+found mnt proc run srv tmp var volume02 dev home lib64 media opt root sbin sys usr volume01 [root@localhost /]# docker run -it --name docker02 --volumes-from docker01 syw/centos:1 .0
关键命令 –volumes-from 只要子容器挂载到父容器上就可以实现容器间的数据互相同步,第三个容器的数据也可以同步到第一、第二个容器中,可以同步多个容器就算删除docker01,docker02依然可以访问这个文件.这是容器间的拷贝的概念
Dockerfile介绍 dockerfile 就是用来构建docker镜像的构建文件 ,命令脚本,使用docker build
简单的Dockerfile例子
1 2 3 4 5 6 7 8 9 10 11 12 # 自己手写一个镜像 # 创建dockerfile,名字可以随机,建议dockerfile # 文件中的内容 指令(大写) 参数 [root@localhost docker-test-volume]# cat dockerfile1 FROM centos # #这里的每一个命令,就是镜像的一层 VOLUME ["/volume01","/volume02"]CMD echo "----end------"CMD /bin/bash # 生成镜像,docker build -f 镜像文件 -t 镜像名:[tag] . [root@localhost docker-test-volume]# docker build -f dockerfile1 -t syw/centos:1 .0 . docker images 就能查到刚刚构建的镜像
如何使用dockerfile 1 2 3 4 1、编写一个dockerfile文件 2、docker build 构建成为一个镜像 3、docker run运行镜像 4、docker push 发布镜像
dockerfile搭建过程 1 2 3 4 1、每个保留关键字(指令)都是必须是大写字母 2、执行从上到下顺序执行 3、#表示注释 4、每个指令都会创建提交一个新的镜像层,并提交
Dockerfile基本命令 1 2 3 4 5 6 7 8 9 10 11 12 FROM #基础镜像,一切从这里开始构建 MAINTAINER #镜像是谁写的,姓名+邮箱 RUN #镜像运行的时候需要运行的命令 ADD #步骤,tomcat镜像,这个tomcat压缩包!添加内容 WORKDIR #镜像的工作目录 VOLUME #挂载的目录 EXPOSE #保留端口配置CMD #指定这个容器启动的时候需要运行的命令 ENTRYPOINT #指定这个容器启动的时候需要运行的命令,可以追加命令 ONBUILD #当构建一个被继承dockerfile 这个的时候就会运行ONBUILD的指令COPY #类似ADD,我们文件拷贝到镜像中 ENV #构建的时候设置环境变量
CMD和ENTRYPOINT的区别 1 2 3 CMD #指定这个容器启动的时候需要运行的命令,只有最后一个会生效,可被替代 ENTRYPOINT #指定这个容器启动的时候需要运行的命令,可以追加命令 一般用ENTRYPOINT结尾
DIY自制Centos镜像 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 FROM centos:7 MAINTAINER handsome<handsome@126 .com> RUN rm -rf /etc/yum.repos.d/CentOS-Base.repo RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7 .repo RUN yum clean all RUN yum makecache ENV MYPATH /usr/local WORKDIR $MYPATH RUN yum -y install vim RUN yum -y install net -tools EXPOSE 100 CMD echo $MYPATHCMD echo "--------end----------"CMD /bin/bash
DIY自制Tomcat镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 FROM centos:7 ADD jdk-8 u152-linux-x64.tar.gz /usr/local ADD apache-tomcat-9 .0 .98 .tar.gz /usr/local RUN rm -rf /etc/yum.repos.d/CentOS-Base.repo RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7 .repo RUN yum clean all RUN yum makecache RUN yum -y install net -tools ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8 .0 _152 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-9 .0 .98 ENV PATH $PATH :$JAVA_HOME/bin:$CATALINA_HOME/lib #设置环境变量 分隔符是: EXPOSE 8080 CMD /usr/local/apache-tomcat-9 .0 .98 /bin/startup.sh && tail -F /usr/local/apache-tomcat-9 .0 .98 /logs/catalina.out # 设置默认命令
SpringBoot微服务打包Docker镜像 1、定义controller
1 2 3 4 5 6 7 8 @RestController("/test") public class TestController { @GetMapping("/aaa") public Object aaa () { return "bbb" ; } }
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > org.example</groupId > <artifactId > dockerfile-test</artifactId > <version > 1.0-SNAPSHOT</version > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.5.6</version > <relativePath /> </parent > <properties > <maven.compiler.source > 8</maven.compiler.source > <maven.compiler.target > 8</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > <configuration > <excludes > <exclude > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </exclude > </excludes > </configuration > </plugin > </plugins > </build > </project >
2、定义Dockerfile
1 2 3 4 5 FROM openjdk:8 COPY *.jar /app.jar CMD ["--server.port=8080" ] EXPOSE 8080 ENTRYPOINT ["java" ,"-jar" ,"/app.jar" ]
3、上传到linux
4、构建镜像
1 2 3 4 5 6 7 8 [root@localhost Dockerfiletest]# ll 总用量 8 -rw-r--r--. 1 root root 112 1 月 23 22 :14 Dockerfile -rw-r--r--. 1 root root 2892 1 月 23 22 :14 dockerfile-test-1 .0 -SNAPSHOT.jar [root@localhost Dockerfiletest]# docker build -t testdockerfile . [root@localhost Dockerfiletest]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE testdockerfile latest f584d98b0712 About a minute ago 526 MB
5、启动容器
1 docker run -d -p 8080 :8080 --name testdockerfile testdockerfile
Docker网络
如上所示,只要装了docker,就会给本机新增一个docker0的网卡。
容器内网络情况
思考: 宿主机能不能ping通容器? 可以相互ping
原理 :我们每启动一个docker容器, docker就会给docker容器分配一个ip, 我们只要安装了docker,就会有一个网卡 docker0桥接模式,使用的技术是veth-pair技术!
1 2 3 4 # 我们发现这个容器带来的网卡都是一对对的, # evth-pair 就是一对虚拟设备接口,它们都是成对出现的,一段连着协议,一段彼此相连 # 正因为这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备 # OpenStack,docker容器间的连接,OVS的连接,都是使用evth-pair 技术
思考:tomcat01、tomcat02 是否可以ping通? 可以
结论:tomcat01和tomcat02是共用一个路由器,docker0
所有容器不指定网络的情况下,都是docker0来路由的,docker会给我们的容器分配一个默认的可用ip,因此tomcat01可以ping通tomcat02
Docker使用的是linux的桥接,宿主机是一个docker容器的网桥
link(不适用当前) 思考一个场景,我们编写了一个微服务,database url=ip: ,项目不重启,数据库ip换掉,我们希望可以处理这个问题,可以名字来进行访问容器。不用网络地址可以ping通
1 2 [root@localhost ~]# docker exec -it tomcat01 ping tomcat02ping: tomcat02 : Name or service not known
如何解决这个问题?
添加了–link 实现容器名ping通,不需要通过网路ip
1 2 3 4 5 [root@localhost ~]# docker run -d -P --name tomcat03 --link tomcat02 tomcat [root@localhost ~]# docker exec -it tomcat03 ping tomcat0264 bytes from tomcat02 (172 .17 .0 .3 ): icmp_seq=74 ttl=64 time =0 .134 ms64 bytes from tomcat02 (172 .17 .0 .3 ): icmp_seq=75 ttl=64 time =0 .156 ms # 反向不能ping 通
–link就是我们在hosts配置中增加了一个 172.17.0.3 tomcat02 容器id 这种格式的host配置,但是这样写的太死了,不可持续,难以维护。
自定义网络 1 2 3 4 5 6 7 8 9 查看所有的docker网络 [root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE cd0629f7a781 bridge bridge local c797f67cfda9 flink_default bridge local83848 de4da79 graylog_graylog bridge local0 d408d098017 host host local345 eb395330e kafka_default bridge local6591455 a2f45 none null local
网络模式
bridge:桥接docker (默认,自己创建的网络也是用bridge 模式)
none:不配置网络
host:和宿主机共享网络
container:容器网络连通(用的少,局限很大)
我们默认启动时其实就是默认 –net bridge,默认使用桥接的docker0这个网络
1 2 3 # 我们直接启动命令,--net bridge,而这个就是我们的docker0 docker run -d -P --name tomcat01 tomcat docker run -d -P --name tomcat01 --net bridge tomcat #等同于上一个命令
自定义网络 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 docker network create mynetwork --driver bridge --subnet 192 .168 .0 .0 /16 --gateway 192 .168 .0 .1 mynetwork是网络名 --driver bridge 是网络模式 --subnet 192 .168 .0 .0 /16 子网是192 .168 .0 .0 前16 位是网络号,后16 位是主机号 --gateway 192 .168 .0 .1 网关是192 .168 .0 .1 #查看刚刚自定义的网络 [root@localhost ~]# docker network list NETWORK ID NAME DRIVER SCOPE cd0629f7a781 bridge bridge local c797f67cfda9 flink_default bridge local83848 de4da79 graylog_graylog bridge local0 d408d098017 host host local345 eb395330e kafka_default bridge local6 cea02844ca7 mynetwork bridge local6591455 a2f45 none null local #启动容器并绑定到自定义的网络 docker rm -f $(docker ps -aq) docker run -d -p 3344 :8080 --name tomcat01 --network mynetwork tomcat docker run -d -p 3345 :8080 --name tomcat02 --network mynetwork tomcat [root@localhost ~]# docker network inspect mynetwork [ { "Name": "mynetwork", "Id": "6 cea02844ca734056bc69f14e79fdce871d2b7f610a402d259345f7dcf294daf", "Created": "2025 -01 -21 T22:07 :18 .289053597 +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": { "567797 a34578a54334a6bb4ac39cf2fc06fc9a322b3cfb49d7956f5b04da73a8": { "Name": "tomcat01", "EndpointID": "0 e85ead22dc53f01ed2fdae970d740a5811e7f6d5a51575a6c69f2514b879c1e", "MacAddress": "02 :42 :c0:a8:00 :02 ", "IPv4Address": "192 .168 .0 .2 /16 ", "IPv6Address": "" }, "a69aeaa3bfef9e7a17b6b77538a1b9e8b9d5d67f457f1181194c3213e0ea46ab": { "Name": "tomcat02", "EndpointID": "1 b45e31f53e87aed935068e6761b35488d1164f2ac9d7f45942d7f551dc427d4", "MacAddress": "02 :42 :c0:a8:00 :03 ", "IPv4Address": "192 .168 .0 .3 /16 ", "IPv6Address": "" } }, "Options": {}, "Labels": {} } ] # 不使用--link都可以ping 通 [root@localhost ~]# docker exec -it tomcat-net -01 ping 192 .168 .0 .3 [root@localhost ~]# docker exec -it tomcat-net -01 ping tomcat-net -02
网络连接 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 [root@localhost ~]# 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 [root @localhost ~]# docker run -d -p 3346:8080 --name tomcat03 tomcat # 连接tomcat03 到自定义网络 mynetwork [root @localhost ~]# docker network connect mynetwork tomcat03 [root @localhost ~]# docker inspect network mynetwork [ { "Name ": "mynetwork ", "Id ": "6cea02844ca734056bc69f14e79fdce871d2b7f610a402d259345f7dcf294daf ", "Created ": "2025-01-21T22 :07:18.289053597+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 ": { "1f85ca4a00dbf7d502ae16564d9694830c5fcff782e2afe3f28590915b8ed789 ": { "Name ": "tomcat03 ", "EndpointID ": "e44f71b65dc14944103448e094dfe4e085cd070495eb006c4cd848e78fa8d10a ", "MacAddress ": "02:42:c0:a8 :00:04", "IPv4Address ": "192.168.0.4/16", "IPv6Address ": "" }, "567797a34578a54334a6bb4ac39cf2fc06fc9a322b3cfb49d7956f5b04da73a8 ": { "Name ": "tomcat01 ", "EndpointID ": "0e85ead22dc53f01ed2fdae970d740a5811e7f6d5a51575a6c69f2514b879c1e ", "MacAddress ": "02:42:c0:a8 :00:02", "IPv4Address ": "192.168.0.2/16", "IPv6Address ": "" }, "a69aeaa3bfef9e7a17b6b77538a1b9e8b9d5d67f457f1181194c3213e0ea46ab ": { "Name ": "tomcat02 ", "EndpointID ": "1b45e31f53e87aed935068e6761b35488d1164f2ac9d7f45942d7f551dc427d4 ", "MacAddress ": "02:42:c0:a8 :00:03", "IPv4Address ": "192.168.0.3/16", "IPv6Address ": "" } }, "Options ": {}, "Labels ": {} } ] # 实现了跨网段用名称进行通信--这样就能ping 通了 [root @localhost ~]# docker exec -it tomcat01 ping tomcat -net -01
结论 我们自定义的网络docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络
好处:
Redis- 不同的集群使用不同的网络,保证集群是安全和健康的
mysql- 不同的集群使用不同的网络,保证集群是安全和健康的
实战:部署Redis集群
测试六台服务器的集群,r-m3宕机,r-s3替补
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 # 通过脚本创建六个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 # 创建结点for port in $(seq 1 6 ); \do \ 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:5 .0 .9 -alpine3.11 redis-server /etc/redis/redis.conf done [root@localhost ~]# 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 >>> 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: 259ef84d4826a362bdc73ad25345513c9ebf9447 172.38.0.11:6379 slots :[0-5460] (5461 slots ) master M : 911abefbfae1d70df6d76003c361f25878ce0e77 172.38.0.12:6379 slots :[5461-10922] (5462 slots ) master M : 5bec694e52aa2bae43dc2755e325e1b0aaf87552 172.38.0.13:6379 slots :[10923-16383] (5461 slots ) master S : e240a6400ca97fc7de11d9d356e88bcc51515508 172.38.0.14:6379 replicates 5bec694e52aa2bae43dc2755e325e1b0aaf87552 S : fd596021d140108df6dda7f2cbcf76261e7aa74f 172.38.0.15:6379 replicates 259ef84d4826a362bdc73ad25345513c9ebf9447 S : fcd076bcd8314f935c1d1b99c47bf5a7b444e443 172.38.0.16:6379 replicates 911abefbfae1d70df6d76003c361f25878ce0e77 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 : 259ef84d4826a362bdc73ad25345513c9ebf9447 172.38.0.11:6379 slots :[0-5460] (5461 slots ) master 1 additional replica (s ) M : 911abefbfae1d70df6d76003c361f25878ce0e77 172.38.0.12:6379 slots :[5461-10922] (5462 slots ) master 1 additional replica (s ) S : fcd076bcd8314f935c1d1b99c47bf5a7b444e443 172.38.0.16:6379 slots : (0 slots ) slave replicates 911abefbfae1d70df6d76003c361f25878ce0e77 S : fd596021d140108df6dda7f2cbcf76261e7aa74f 172.38.0.15:6379 slots : (0 slots ) slave replicates 259ef84d4826a362bdc73ad25345513c9ebf9447 S : e240a6400ca97fc7de11d9d356e88bcc51515508 172.38.0.14:6379 slots : (0 slots ) slave replicates 5bec694e52aa2bae43dc2755e325e1b0aaf87552 M : 5bec694e52aa2bae43dc2755e325e1b0aaf87552 172.38.0.13:6379 slots :[10923-16383] (5461 slots ) master 1 additional replica (s ) [OK ] All nodes agree about slots configuration . >>> Check for open slots ... >>> Check slots coverage ... [OK ] All 16384 slots covered . #至此docker 搭建redis 集群完成!
测试节点宕机,从节点提供服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #进入redis-1 [root@localhost ~]# docker exec -it redis-1 #查看集群信息172 .38 .0 .11 :6379 > cluster nodes259 ef84d4826a362bdc73ad25345513c9ebf9447 172 .38 .0 .11 :6379 @16379 myself,master - 0 1737557695000 1 connected 0 -5460 911 abefbfae1d70df6d76003c361f25878ce0e77 172 .38 .0 .12 :6379 @16379 slave fcd076bcd8314f935c1d1b99c47bf5a7b444e443 0 1737557695528 7 connected fcd076bcd8314f935c1d1b99c47bf5a7b444e443 172 .38 .0 .16 :6379 @16379 master - 0 1737557695000 7 connected 5461 -10922 fd596021d140108df6dda7f2cbcf76261e7aa74f 172 .38 .0 .15 :6379 @16379 slave 259 ef84d4826a362bdc73ad25345513c9ebf9447 0 1737557694514 5 connected e240a6400ca97fc7de11d9d356e88bcc51515508 172 .38 .0 .14 :6379 @16379 slave 5 bec694e52aa2bae43dc2755e325e1b0aaf87552 0 1737557694109 4 connected5 bec694e52aa2bae43dc2755e325e1b0aaf87552 172 .38 .0 .13 :6379 @16379 master - 0 1737557695629 3 connected 10923 -16383 #设置a的值172 .38 .0 .15 :6379 > set a bbb -> Redirected to slot [15495 ] located at 172 .38 .0 .13 :6379 停用redis-3 的容器服务127 .0 .0 .1 :6379 > get a -> Redirected to slot [15495 ] located at 172 .38 .0 .14 :6379 "bbb"
Docker Compose 简介 简单来说,Docker Compose是Docker开源的另一个项目,来轻松高效的管理容器,定义运行多个容器。
Dockerfile build run 只能启动一个容器,如果有多个容器,可以借助docker-compose.yaml定义文件和docker-compose up -d 命令启动来编排和定义先后依赖关系,做到批量启动。
安装 参考前文
命令 只构建镜像
当构建文件(Dockerfile)出错时,修改后,加build会重新构建
只下载镜像docker-compose.yml文件中的镜像
启动容器,-d后台启动
执行此命令会先pull后启动
查看使用docker-compose.yml启动的容器
临时进入docker-compose.yml启动的容器(查看不到)
1 docker-compose run 容器名 /bin/sh
启动docker-compose.yml中的容器
停止docker-compose.yml中的容器
删除使用docker-compose.yml运行的容器(需要先stop)
YAML规则 https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples
docker-compose.yaml 的语法规则,包括版本、服务(含众多服务关键字)、网络(含网络关键字)、卷、配置项、密钥等的定义
docker-compose.yaml举例
主要有几个部分组成:version、services、volumes、networks,每个service的内容与每个dockerFile定义镜像类似的去describe每个服务的信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 version: "3" services: server_name: container_name: container_name image: xxx:latest build: context: /xxx/xxx/Dockerfile dockerfile: .... ports: - "00:00" - "00:00" volumes: - test1:/xx/xx - test2:/xx/xx - test3:/xx/xx volumes_from: - volume_container_name restarts: always depends_on: - server_name - server_name1 links: - mysql networks: - my_net - myapp_net environment: - TZ=Asia/Shanghai 变量值: 变量名 command: [ '--character-set-server=utf8mb4' , '--collation-server=utf8mb4_unicode_ci' , '--default-time-zone=+8:00' ] server_name2: server_name: stdin_open: true tty: true volumes: test1: test2: test3: networks: my_net: driver: bridge myapp_net: driver: bridge
Docker Swarm docker:容器
docker-compose:一个节点上的一系列容器
docker-swarm:多个主机或者集群上的多套环境容器的管理大规模容器化应用,
docker-swarm对标K8S
不过业界用docker-swarm比较少,学习意义不大