Docker为什么出现?
解决开发和运维环境的不同导致的各种问题
隔离打包封装
Docker历史
2010年,美国成立了一家公司dotCloud,做一些pass的云计算服务,LXC有关的容器技术,他们将自己的技术(容器化技术)命名为Docker!Docker刚诞生的时候,没有引起行业的注意!dotCloud快活不下去了
2013年的时候,将docker开源!自此开始火起来。每月都更新一个版本!
2014年4月9日,Docker1.0发布!
Docker为什么这么火?
在容器之前,都是使用虚拟机。
虚拟机:在window上安装Vmware,通过这个软件就能虚拟出来一台电脑,缺点就是占空间!
Docker也是基于虚拟化技术,但是Docker是容器技术。优点:核心是镜像(最小环境4m,mysql)
What can do in Docker ?
虚拟机技术
docker技术
Docker和虚拟机对比:
传统虚拟机,虚拟一套硬件出来,运行一个完整的系统
容器直接运行在宿主机上的内容,容器没有内核,运行速度较快
每个容器之间相互隔离,每个容器拥有属于自己的文件系统,互补干扰
DevOps(开发、运维)
传统:一堆文档,安装程序
Docker:打包镜像发布和测试,一键运行
项目打包为一个镜像(带环境的包),拓展 服务器1-N
更简单有效的运维
更高效的计算资源利用
Docker是内核级别的虚拟化,可以在物理机上可以运行N个Docker实例!把服务器性能压榨到极致
Docker的基本组成
镜像(image):
docker镜像就像一个模板,可以通过模板可以创建容器服务,mysql镜像==>run==>mysql容器(提供服务),通过这个镜像可以创建多个容器(最终运行或项目运行在容器中)
容器(container):
Docker利用容器技术,独立运行一个或一个组应用,通过镜像来创建。
基本命令
启动
停止
删除
简易的linux系统
仓库(repository):
存放镜像的地方
仓库分为公共仓库和私有仓库
Docker Hub(默认国外)
阿里云容器服务(配置镜像加速)
安装Docker
环境查看:
# 系统内核
$ uname -r
3.10.0-1127.19.1.el7.x86_64
# 系统版本
$ cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
Docker安装
# 卸载旧版环境
$ yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 安装需要的安装包
$ yum install -y yum-utils
# 设置镜像仓库
$ sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 更新软件包索引
$ yum makecache fast
# 安装最新版引擎和依赖包 docker-ce 社区版 docker-ee 企业版
$ yum install docker-ce docker-ce-cli containerd.io
# 启动docker
$ systemctl start docker
# 查看docker 信息
$ docker version
# 测试docker
$ docker run hello-world
# 查看镜像
$ docker images
# 卸载docker
# 卸载依赖
$ yum remove docker-ce docker-ce-cli containerd.io
# 删除目录
$ sudo rm -rf /var/lib/docker
配置阿里云镜像加速
$ sudo mkdir -p /etc/docker
$ sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://a3crls50.mirror.aliyuncs.com"]
}
EOF
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
docker run运行流程图
底层原理
Docker是怎么工作的?
Docker是一个CS结构的系统,Dockerde守护进程运行在主机上。通过Socket从客户端访问!DockerServer接受Docker-Client的指令去执行这个命令。
Docker为什么比VM快?
Docker比虚拟机更少的抽象层
Docker利用的是宿主机的内核,VM需要的是Guest OS
新建一个容器的时候,不需要在去运行一个虚拟机
Docker常用的命令
帮助命令
# docker版本信息
$ docker version
# docker系统信息,包括镜像和容器的数量
$ docker info
# 帮助命令
$ docker help
镜像命令
$ docker images [OPTIONS] [REPOSITORY[:TAG]]
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mongo latest 409c3f937574 9 days ago 493MB
scrapinghub/splash latest 9364575df985 10 days ago 1.89GB
redis latest 1319b1eaa0b7 3 weeks ago 104MB
mysql latest 0d64f46acfd1 3 weeks ago 544MB
# Column 名词解释
REPOSITORY 镜像仓库源
TAG 镜像版本标签
IMAGE ID 镜像ID
CREATED 镜像创建的时间
SIZE 镜像大小
# 可选项
-a, --all 列出所有镜像
-q, --quiet 只显示镜像ID
镜像查找
$ docker search mysql
# 通过收藏来过滤
--filter=STARS=3000 # 搜索STARS大于3000
下载镜像
$ docker pull mongo:latest
Using default tag: latest # 如果不写tags,默认latest
latest: Pulling from library/mongo
f08d8e2a3ba1: Already exists # 核心分层下载,docker images的核心,联合文件系统
3baa9cb2483b: Already exists
94e5ff4c0b15: Already exists
1860925334f9: Already exists
9d42806c06e6: Already exists
31a9fd218257: Already exists
5bd6e3f73ab9: Already exists
f6ae7a64936b: Already exists
80fde2cb25c5: Already exists
1bec62fe62fc: Already exists
2cf4970a1653: Pull complete
39fac3226e16: Pull complete
86bca9c64faf: Pull complete
Digest: sha256:df9eca84736a666d5f7e7a09aeb8a6d8d073698d5b7349400f10ee75812e0e95 # 签名
Status: Downloaded newer image for mongo:latest
docker.io/library/mongo:latest # 真实地址
# 指定版本下载
docker pull mysql:5.7
删除镜像
# 删除一个或多个镜像
$ docker rmi -f TAGS/RESPOSITORY
# 删除全部镜像
$ docker rmi -f $(docker images -aq)
容器命令
说明:有了镜像才能创建容器,下载一个centos镜像来测试学习以下
$ docker pull centos
**新建并启动容器**
$ docker run [可选参数] image
# 参数说明
--name="Name" 容器名字, tomcat1 tomcat2,用来区分容器
-d 后台交互式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 主机端口:容器端口
# 进入容器
$ docker run -it centos /bin/bash
[root@5c14e9010f22 /]# # root@镜像id
# 退出容器并停止容器
$ exit
# 容器退出不停止容器
Ctrl+Q+P
列出运行中的容器
# 列出正在运行的容器
$ docker ps
# 可选项
-a 列出所有容器
-n=? 显示最近创建的容器
-q 只显示容器的编号
删除容器
# 删除指定id的容器,不能删除正在运行的容器
$ docker rm 容器id
# 强制删除
$ docker rm -f 容器id
# 删除所有容器
$ docker rm -f $(docker ps -aq)
$ docker ps -a -q |xargs docker rm
启动和停止容器的操作
# 启动容器
$ docker start CONTAINER ID
# 重启容器
$ docker restart CONTAINER ID
# 停止当前运行的容器
$ docker stop CONTAINER ID
# 强制停止当前运行的容器
$ docker kill CONTAINER ID
其他命令
$ docker run -d image
#docker ps 发现没有centos运行
# 原因是docker容器使用后台运行,就必须要一个前台进程,docker发现没有应用,就会停止
查看日志
$ docker logs -f -t --tail CONTAINER ID
# 容器没有日志
# 写一段shell脚本
$ docker run -d centos /bin/sh -c "while true;do echo zxq;sleep 1;done"
# 显示指定行数的日志
docker logs -tf --tail 10 CONTAINER ID
**查看容器中进程信息**
$ docker top CONTAINER ID
UID PID PPID C STIME TTY
TIME CMD
root 13362 13345 0 18:12 ?
00:00:00 /bin/sh -c while true;do echo zxq;sleep 1;done
root 13680 13362 0 18:16 ?
00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
查看容器的元数据
$ docker inspect CONTAINER ID
进入当前正在运行的容器
# 我们的容器通常使用后台方式运行的,需要进入到容器,修改一些配置
$ docker exec -it CONTAINER ID /bin/bash
# 进入正在执行中的代码
$ docker attach CONTAINER ID
# 区别
$ docker exec 进入容器后开启一个新的终端
$ docker attach 进入容器正在执行的终端,不启动新终端
从容器内拷贝文件到宿主机上
$ docker cp CONTAINER ID:容器内路径 宿主机路径
Docker安装Nginx
搜索镜像 https://hub.docker.com/
下载镜像
$ docker pull nginx
- 运行测试
$ docker run -d --name nginx01 -p 3306:80 nginx
$ curl localhost:3306
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
- 进入容器
$ docker exec -it nginx01 /bin/bash
- 思考:我们每次改动Nginx配置文件,都要进入容器内部?十分麻烦,我要是可以在容器外部提供一个映射路径,达到在容器外部修改文件,容器内部自动修改?-v 数据卷技术
Docker安装elastucsearch+kibanna
注意:es暴露的端口很多!
es十分耗内存
es的数据一般需要放置到安全目录!挂载
# --net somenetwork Docker网络配置
$ docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:latest
# 启动linux服务器卡住
$ docker stats
# 操作内存限制,修改配置i文件 -e 环境配置修改
$ docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:latest
可视化
portainer
Rancher(CI/CD)
什么是portainer?
Docker图形化管理工具,提供一个后台面板供我们操作!
$ docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
Docker 镜像
镜像是什么
镜像是轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
如何得到镜像:
从远程仓库下载
朋友打包给你
自己制作
UnionFS(联合文件系统)
我们下载的时候看到一层层的文件系统组成的,这就是联合文件系统。
例如:
-
centos
-
mysql
- …
-
Docker 镜像加载的原理
bootfs ,主要包含bootloader和kernel,而bootloader主要时引导加载kernel,Linux刚启动时就会记载bootfs文件系统,在Docker镜像的最底层的就是bootfs,这一层和典型的Linux一样的,包含boot加载器和内核,当boot加载完成整个内核都在内存中了,此时内存的使用权已经由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs 文件,在bootfs之上,包含电线杆的Linux系统中额/dev,/proc,/bin,/etc等标准目录 和文件。rootfs就是各种不同系统发行版,比如Ubuntu,Centos等。
对于一个精简OS镜像,rootfs可以很小,只需要包含基本的命令,工具和程序库就可以了,因为底层直接调用Host的kernel,自己只需要提供rootfs就可以了,
分层理解
所有的layer合并
特点
Docker 镜像都是只读的,当容器启动的时候,一个新的可写层就被加载到镜像的顶部,这一层就是容器层,容器层以下都是镜像层
commit镜像
# 提交容器成为一个新的副本
$ docker commit -m="提交的描述" -a='author' containerid 目标镜像名:[TAG]
案例
启动一个默认的镜像
把文件拷贝进去镜像中
将我们操作过的容器通过commit提交为一个镜像,以后我们就使用修改过的镜像
容器数据卷
什么时容器数据卷?
将应用和环境打包成镜像!
数据?如果在容器中,那么我们容器删除了,数据就丢失!需求:数据持久化
Mysql,容器删了,删库跑路!
容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂在,将我们的容器内的目录,挂在到Linux上。
使用数据卷
方法1
$ docker run -it -v -p 主机目录:容器内目录 镜像名 /bin/bash
文件系统,双向同步的,
我们以后修改只需要在本地修改即可。
安装MySQL
# 拉取镜像
$ docker pull mysql
#第一次启动mysql需要配置mysql 加上下面参数
$ -e MYSQL_ROOT_PASSWORD=my-secret-pw
# 启动mysql
$ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf -v /home/mysql/data:/var/lib/mysql
具名和匿名挂载
# 匿名挂载 只写了容器内的路径
$ docker run -d -P --name nginx01 -v /etc/nginx nginx
# 具名挂载
$ docker run -d -P --name nginx02 -v 卷名:/etc/nginx nginx
# 查看所有卷情况
$ docker volume ls
# 所有的docker容器内的卷,没有指定目录的情况下在 /var/lib/docker/volumes/卷名/_data
# 通过具名挂载可以方便我们的一个卷,大多数情况下使用具名挂载
Usage: docker volume COMMAND
Commands:
create 新建一个卷
inspect 显示一个或多个卷的具体信息
ls 列出所有卷
prune 删除所有本地没有用过的卷
rm 删除一个或多个卷
拓展:
# 一旦设置了容器权限,容器对我们挂载出的内容就有限定了
# ro(readonly)只能读,只能通过宿主机来更改内容,容器内部无法操作
$ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
# rw(readwrite)可读可写,默认是rw
$ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
方式二:
通过脚本可以生成镜像
# 创建一个dockerfile文件,名字随意
# 文件中内容 指令(大写) 参数
FROM centos #
VOLUMES ['volume01','volume02']
CMD echo "----end-----"
CMD /bin/bash
# 这里的每个命令,就是镜像的一层
# 启动自己生成的镜像
$ docker run -it IMAGE ID /bin/bash
$ ls -la
# 可以看到自己设置的数据卷,这个卷和外部是有一个同步目录的
# 查看卷挂载的路径
$ docker inspect CONTAINER ID
# 查看文件是否同步出去了
$ cd /var/lib/docker/volumes/镜像id/_data
数据卷容器
多个mysql数据同步!
# 启动三个容器,通过我们刚才写的容器
$ docker run -it --name docker01 jonescy/centos:1.0
# 第二个容器继承docker01
$ docker run -it --name docker02 --volumes-from docker01 jonescy/centos:1.0
# 第三个容器继承docker01
$ docker run -it --name docker03 --volumes-from docker01 jonescy/centos:1.0
# 例如我们在docker01 中建立第一文件test.py,在docker02/docker03都是能看到的,
# 测试:现在我吧docker01 删除了,数据依然在docker02和docker03中可以访问这个文件
# 这是一种备份机制
案例:多个MySQL实现数据共享
$ docker run -d -p 3306:3306 -v /etc/mysql/conf -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=1997 --name mysql01 mysql
$ docker run -d -p 3306:3306 - -e MYSQL_ROOT_PASSWORD=1997 --name mysql02 --volumes-from mysql01 mysql
# 这个时候就可以实现 2个容器实现数据同步
结论:
应用在做集群的情况,容器之间配置信息的传递,通过数据卷容器实现数据同步,生命周期一直会持续到没有容器使用为止。
DockerFile
Dockerfile 就是用来构建docker 镜像的构建文件,命令参数脚本!
构建步骤:
编写dockerfile 文件
docker build 构建成为一个镜像
docker run 运行镜像
docker pull
DockerFile构建过程
基础知识:
每个保留关键字(指令)都必须是大写字母
执行至上而下
-
注释
-
每个指令都会创建一个新的镜像层,并提交
dockerfile是面向开发的,以后发布项目,做镜像,就要编写dockerfile文件,这个文件十分简单
Docker镜像逐渐称为企业交付的标准,必须遵守
步骤:开发 ->部署-> 运维
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构成的镜像,最终发布和运行的产品
Docker Container:容器就是镜像运行起来提供服务器的
DockerFile指令
FROM # 基础镜像,一切从这里构建
MAINTAINER # 维护者信息(谁写的:姓名+邮箱)
RUN # 镜像构建需要运行的命令
ADD # 步骤:tomcat镜像,这个tomcat压缩包!添加的内容
WORKDIR # 镜像工作目录 /bin/bash
VOLUME # 挂载的目录
EXPOSE # 保留端口的位置
CMD # 指定这个容器启动的时候运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定这个容器启动的时候运行的命令,可以追加命令
ONBUILD # 当构建一个被继承DockerFile这个时候就会运行ONBUILD的指令。触发指令
COPY # 类似ADD,将我们文件拷贝到镜像中
ENV # 构建的时候设置环境变量
案例:自己写centos
Docker Hub中99%镜像都是从这个基础镜像过来的FROM scratch,然后配置需要的软件和配置来进行构建
创建一个自己的Centos
# 自己编写DockerFile文件
FROM centos
MAINTAINER Jonescy
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
# 通过这个文件构建镜像
$ docker build -f dockerfile文件路径 -t 镜像名:版本号
# 测试运行
对比:之前的原生centos
# 查看镜像生成的操作
$ docker history imageid
CMD和ENTRYPOINT区别
测试CMD
# 构建dockerfile
[root@jonescy dockerfile]# vim dockerfile-test-cmd
FROM centos
CMD ["ls","-a"]
#构建镜像
[root@jonescy dockerfile]# docker build -f dockerfile-test-cmd -t cmdtest .
Successfully built 6d9b167cb82b
Successfully tagged cmdtest:latest
# 运行cmd ,ls -a 生效
[root@jonescy dockerfile]# docker run -it 6d9b167cb82b
. .dockerenv dev home lib64 media opt root sbin sys usr
.. bin etc lib lost+found mnt proc run srv tmp var
[root@jonescy dockerfile]# docker run -it 6d9b167cb82b -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
# 在cmd的情况下 -l 替换了CMD ['ls',"-a"]命令,-l不是命令所以报错
测试ENTRYPOINT
$ vim dockerfile-entorypoint
FROM centos
ENTRYPOINT ["ls","-a"]
$ docker build -f dockerfile-entorypoint -t entrypoint .
Successfully built 8cd2f7672d27
Successfully tagged entrypoint:latest
$ docker run entrypoint:latest
$ docker run entrypoint:latest -l
# 这里会输出ls -la的内容,证明了。entrypoint的命令可以追加参数,不会替换ls -a命令
案例:Tomcat镜像
-
准备镜像文件 tomcat压缩包,jdk压缩包!
- 编写dockerfile文件,官方命名
Dockerfile
,可以省略-f参数
FROM centos
MAINTAINER jonescy
COPY readme.txt /usr/loacl/readme.txt
ADD jdk-8u261-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.37.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORK $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.37
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.37
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.37/bin/startup.sh && tail -F /usr/loacl/apache-tomcat-9.0.37/bin/logs/cataline.out
- 构建镜像
$ docker build -t
- 启动镜像
$ docker run -d -p 8080:8080 --name jonescytomcat -v/home/Tomcat/test:/usr/loacl/apache-tomcat-9.0.37/webapps/test -v /home/Tomcat/tomcatlogs:/usr/loacl/apache-tomcat-9.0.37/logs diytomcat
- 访问测试
$ docker exec -it container id /bin/bash
-
发布项目(由于做了卷挂载,我们可以直接在本地编写)
# web.xml
struts2 org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter struts2 /* index.jsp
# index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
jonescy
项目发布完成
我们以后的开发步骤:需要掌握Dockerfile的编写
发布项目
Docker Hub
注册自己的账号:https://www.docker.com/products/docker-hub
确定这个账号可以登录
在服务器上登录Docker Hub账号
$ docker login -u -p
- 登录过后,提交镜像
# 更改tag的时候,要注意带上作者名/new-repo:tagname
$ docker tag local-image:tagname authorname/new-repo:tagname
$ docker push new-repo:tagname
阿里云镜像仓库
登录阿里云
找到容器镜像服务
-
创建命名空间
目的是为了隔离,一般以一个项目为一个空间
创建镜像仓库
-
本地推送到仓库
# 登录阿里云Docker Resgistry $ sudo docker login --username=jonescy registry.cn-shenzhen.aliyuncs.com # 推送到阿里云服务上 $ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/jonescy-aliyun-docker/tomcat:[镜像版本号] $ sudo docker push registry.cn-hangzhou.aliyuncs.com/jonescy-aliyun-docker/tomcat:[镜像版本号] # 拉取阿里云上的镜像 sudo docker pull registry.cn-shenzhen.aliyuncs.com/jonescy-aliyun-docker/tomcat:[镜像版本号]
阿里云容器镜像服务
小结
Docker网络
理解docker0
$ docker run -d -P --name tomcat01 tomcat
# 查看容器内部地址 ip addr
$ docker exec -it tomcat01 ip addr
1: lo: 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
90: eth0@if91: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# linux 可以ping通docker容器内部
$ ping 172.17.0.3
原理
-
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术
# 在运行一个容器测试一下 $ docker run -d -P --name tomcat02 tomcat # 看下图可以发现一个又新增了一个网卡
-
在启动容器的时候服务器会新建一个网卡,与容器内部的相一致
这就是evth-pair 技术 ,它是一堆虚拟设备接口,他们都是成对出现的,一段连接着协议,一段彼此相连,因为有了这个特性,evth-pair充当一个桥梁,连接各种虚拟网络设备。Openstac,Docker容器之间的连接,OVS的连接,都是使用evth-pair 技术
-
测试下tomcat01和tomcat02是否能ping通,结果显而易见也是能通的。
- docker容器间的通信,可以想象成我们的家庭组网,Docker比作路由器地址为172.17.0.1,自动给容器分配IP地址,docker容器就像我们联网的设备例如图上的例子,tomcat01:ip地址为172.17.0.3,tomcat02:IP地址为172.17.0.4,它们在同一个网段下,是可以互联互通的。
Docker使用的是Linux的桥接,宿主机中是一个Docker容器的网桥 docker0
Docker中的所有网络接口都是虚拟接口。虚拟接口转发效率高,只要容器删除,虚拟网卡也删除了。
案例:ip在变,通过容器名来访问容器
--link(限制太大,不建议使用)
解决 容器间不能直接通信的问题
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat
# 通过--link 即可解决网络连通的问题
$ docker exec -it tomcat03 ping tomcat02
# 但是不能够反向连通
# 通过inspect 查看元数据
$ docker network inspect ID
# tomcat03 配置了tomcat02的网络设置
# /etc/hosts 查看网络绑定的配置
$ 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.4 tomcat02 8596a53d2d80
172.17.0.5 6a067ce79653
$ docker exec -it tomcat02 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.4 8596a53d2d80
# 对比发现 --link 就是在我们的hosts配置中增加了一个tomcat02的映射,而tomcat02中没有映射到tomcat03中,所有不能从tomcat02 ping tomcat03
# 在tomcat02上手动绑上tomcat03的映射
# 但是--link太局限于docker0,docker0不支持容器名连接访问
自定义网络(容器互联)
查看所有的docker网络
网络模式:
bridge:桥接模式(自己创建的网络,也使用桥接模式)
none:不配置网络
host:主机模式(和linux服务器共享的网络)
container:容器网络连通!(用的少)
案例:自定义网络(推荐使用)
# 直接启动命令 默认是 --net bridge
$ docker run -d -P --name tomcat01 --net bridge tomcat
# docker0特点:默认,域名不能访问,--link可以打通连接
# 创建自定义网络
$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 使用我们自定义的网络,容器就可以互联了
$ docker exec -it tomcat-net-01 ping tomcat-net-02
好处:
mysql -不同的集群使用不同的网络,保证集群是安全和健康的
redis -不同的集群使用不同的网络,保证集群是安全和健康的
不同集群或不同网段间的网络连通
# 测试打通tomcat01 - mynet
$ docker network connect mynet tomcat01
# 连通之后,tomcat01是直接增加到mynet这个网段中,实现互联。
# 这就是所谓的一个容器2个IP 。例子:阿里云服务器:公网ip和私网ip
案例:部署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 </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
# 运行6个redis容器脚本
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
# 创建集群
$ 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