Docker基础
Docker学习笔记
容器化技术介绍
历史演变
应用的部署演化主要有三个阶段:
物理机时代
在物理机时代,应用部署在物理机上。那么如果想要安装一个软件,需要准备一台物理机,并在这个物理机上安装操作系统,然后安装各种各样的为了软件能够运行所需要的插件、资源等。物理机时代有如下缺点:
- 安装部署慢:在物理机上部署应用,需要为应用的运行环境做准备。例如:运行java应用,就要安装jre,运行python就要安装python...
- 成本很高:每一个应用不是在一个物理机上。为了应用的稳定性,一般都会部署多个实例,那么就需要准备多个物理机。而一台物理机包括cpu,内存,磁盘等,如果应用对性能要求较高的话,那么对硬件是要求很高的,组装一台物理机的成本也很高。
- 资源浪费:物理机上安装应用,对资源的使用是不平衡的。如果应用是存储类型的,那么对磁盘,内存等要求会很高,而对cpu要求不高。如果应用是计算型的,那么就对cpu要求很高,而对磁盘内存等要求就不高。因此物理机需要针对应用配置不同的硬件,比较繁琐,否则就会导致资源浪费。而这个硬件资源的平衡点又不好取。
- 难于扩展和迁移:如果想要对应用做横向扩展,如果只是加内存还好,如果想要扩展实例重新部署一台,那么新的服务器也需要安装各种各样的运行环境,配置各种各样的参数等,比较繁琐且容易出错。如果是想要将应用从旧的win服务器,转到高性能的linux服务器,那么如果软件只能在win系统上运行的话,就会出问题。
- 受限于硬件:可能会产生硬件兼容性问题。
虚拟机时代
由于物理机时代的各种各样的问题,为了解决这些问题,进入了虚拟机时代。虚拟机是建立在物理机之上的。
虚拟机具有如下特点:
-
多部署:一台物理机上可以部署多个虚拟机
-
资源池:多个虚拟机共享物理机所拥有的资源。
Host Operation System
是物理机所拥有的资源,虚拟机的资源统一通过Hypervisor
来分配。 -
资源隔离:虚拟机之间资源是完全隔离的,因此一台虚拟机出问题,不会影响其他虚拟机的运行
-
容易扩展:虚拟机的拓展非常方便,由于虚拟机的资源统一通过
Hypervisor
来分配,因此只要硬件资源够大,那么很方便就可以扩展一个新的虚拟机。 -
需要安装操作系统:上面的都是虚拟机的优点。虚拟机就是相当于在硬件操作系统的基础上又重新创建了一套虚拟的操作系统,虚拟操作系统之间隔离。因此想要使用一个虚拟机就需要安装一个操作系统。这也是虚拟机最大的缺点。可能我一个应用只有几百kb,而且运行时所需要占用的资源也不是很多,但是为了支撑这个应用,就需要安装一个操作系统,一个操作系统占用的最小资源也得几百兆。同时虚拟机占用的cpu内存资源等也比这个微小的应用要高的多。
而一个物理机上可能会安装几十个虚拟机,如果每个虚拟机上只安装一个上面这种小的应用,那么操作系统浪费的资源会多得多。会造成很大的资源浪费。
为了解决上面的问题,由于我们关心的只有应用软件的运行,因此就有人想,能不能把app从操作系统中剥离出来,因此就进入了容器化时代。
容器化时代
容器化技术可以看成是一个不需要安装操作系统的虚拟机。这样描述可能不太准确,但是可以先这样去简单理解。
右图是虚拟机模型:每一个虚拟机都需要安装Guest OS
--客户操作系统,然后在客户操作系统之上安装app及各种类库。
左图是容器化模型:Docker
只是容器化的一个典型代表,Docker
安装在主操作系统之上,然后通过Docker
的沙箱机制隔离出一个一个的容器,容器只包含app和类库,不包含操作系统,所以体积是非常小的。
容器化技术并不会取代虚拟化技术
虚拟化主要是物理资源层面的隔离。例如为每个虚拟机分配多少的内存,分配几核的cpu。而容器化技术,所有的容器都是共同运行在物理资源上的,物理资源不隔离,应用隔离,应用之间不会互相影响。
虚拟化和容器化技术混合运用场景
-
如阿里云,腾讯云的服务器性能好:采用的是虚拟机和容器化技术的实现
-
比如在阿里云购买ECS服务器,在阿里云那边就是一个虚拟机,根据应用场景不同,安装不同容器,比如购买阿里云的mysql数据库,阿里云通过容器化技术自动安装mysql容器,就得到一台mysql服务器了,这里虚拟化主要是对硬件资源的隔离,但在虚拟机中所使用到的mysql是通过容器化技术部署的
容器化解决的问题
在我之前的公司,使用的是虚拟化技术。而且当时项目没有使用springboot
,因此当时项目打出来的压缩包,项目包和类库包是两个文件夹的。
当时在上线项目前,我们开发需要准备:项目及类库压缩包、环境变量修改项整理一个文件、上线操作步骤要整理文档、如果需要安装sdk等,还需要准备sdk文件及安装方式。然后上线时,运维按照操作步骤文档,将jar包放入文档上写的位置,安装sdk等,配置环境变量,导入种子数据等....
经过了一系列繁琐的操作,终于完成,项目启动......... 报错。然后又是一系列的排查,结果发现给的文档里路径写错了/环境变量写错了等。
而使用容器化技术后,开发人员会将项目打成一个镜像--app容器。镜像内包含了所有项目启动需要的类库、变量配置、数据、sdk等。只要这个镜像经过层层测试,没有问题可以上线了。那么直接把这个镜像发送给运维,运维直接部署这个镜像,这样就避免了上面虚拟化的那些问题。
容器化的特点
经过上面的简单了解,可以总结出容器化具有如下特点:
- 标准化的迁移方式:应用统一通过镜像来部署,迁移时只需要拿到镜像就可以了。
- 统一的参数配置:参数也一块打包进镜像里了。
- 自动化部署:只需要提供镜像,
Docker
会自动将镜像还原成应用并进行部署启动。 - 应用集群监控:容器化技术是自带健康检查的,可以很轻松的查到出问题的应用。
- 开发与运维之间沟通的桥梁:使用容器化技术后,减少了运维的工作量,也避免了上线出问题,开发和运维之间甩锅的情况。
Docker介绍
docker是一个容器化平台,主要可以分为如下三层:
-
应用程序:部署的具体的应用服务
-
Docker引擎
:docker引擎是一个中间层,从下层物理机获取可用资源,再通过docker引擎为app分配提供可用资源。应用程序不直接访问底层资源,通过docker中间层操作。docker
引擎结构如下:docker client
: docker客户端,提供交互命令rest api
: 通讯层,docker client
通过rest api
将操作命令传达给docker server
。rest api
是http协议的一种规范,由于使用http协议,因此docker的兼容性和可拓展性都很好docker server
:也称为docker demon
守护进程,所有docker服务都是通过docker daemon
完成,如容器的获取,镜像的创建等
-
可用资源:只物理机/虚拟机的内存,cpu,磁盘等硬件资源
docker的特点
-
开源的应用容器引擎,基于go语言开发
-
容器完全使用沙箱机制,容器开销极低,反向提升系统利用率
-
Docker具备虚拟化职能,可以创建容器,还可向本地的物理机申请资源,更加方便程序的迁移与扩展。
-
基于cs架构,拥有服务端和客户端的架构
cs架构的优势:服务器和客户端不用安装一台电脑上,可以使运维工程师用一台电脑对很多台服务器进行管理
-
Docker提供标准的应用打包的方式,集装箱是镜像文件,镜像文件中包含了所有的资源,如web引用,数据库,web应用服务器,队列等,在这个镜像中还用来描述这些应用所需要的硬件环境要求,部署后也可灵活的调整,运维工程师得到镜像文件后,方便的进行扩展与还原,马上能得到与之前一样的运行环境。这也是docker存在的意义。
镜像和容器的区别
-
镜像:镜像是只读的文件,提供了运行程序完整的软硬件资源,是应用程序的"集装箱"
-
容器:是镜像的实例,由Docker负责创建,如windows光盘与实际安装的PC机,又或者java之中的Class类和new出来的对象的关系,容器直接相互隔离,互不影响
docker工作流程
工作流程如下图:
client
通过rest api
发送命令docker pull
到docker host
docker host
中的docker daemon
接收并处理命令docker daemon
查看本地仓库images
中是否有镜像,如果没有镜像就到registry
远程仓库中拉取镜像到本地仓库- 发送
docker run
命令到server端
,docker daemon
通过镜像创建容器运行
Docker的安装
由于本地安装的虚拟机是ununtu
,所以下面是安装步骤是在ubuntu
上安装的,其他途径的安装,官方文档上都有很详细的步骤。本次安装也是按照官网步骤来的。推荐使用centos系统,因为centos是使用最广泛的服务器系统
# centos yum源加速
# yum install -y yum-utils device-mapper-persistent-data lvm2
-y 自动确认安装
yum-utils是yum安装的工具包,简化安装过程中设置安装源的配置过程
安装数据存储驱动包,docker内部存储通过这2个组件完成数据存储
# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
修改yum的安装源,设置新的安装源,路径为国内阿里云的安装源
设置新的安装源目的:docker安装源默认是在国外,下载的非常慢
# yum makecache fast
让安装源自动检测速度是最快的,优先使用它
卸载旧的版本
如果本地没有安装过docker,可以跳过此步骤
$ sudo apt-get remove docker docker-engine docker.io containerd runc
设置存储库
更新apt软件包索引
$ sudo apt-get update
$ sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
添加docker官方gpg密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
设置稳定存储库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
安装docker引擎
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
- 关于
docker-ce
:docker-ce
代表是社区版免费,docker-ee
是企业版收费
运行hello-world验证docker引擎是否安装正确
$ sudo docker run hello-world
启动成功
client
:代表客户端的版本server
:代表服务端的版本
阿里云加速
docker默认会从国外的docker中央仓库下载镜像。但是由于国内网络的特殊性,从国外下载非常慢。可以通过配置从阿里云的容器镜像下载docker镜像。
登陆阿里云官网,搜索容器镜像服务
点进进入,并进入管理控制台界面
按照下面的操作文档去配置加速。
Docker命令
docker镜像版本查询
在hub.docker.com
网站中搜索查看是否拥有对应的镜像。否则会拉取不到镜像
-
不建议使用第三方镜像。也许存在bug,恶意代码等。
-
建议使用官方镜像,官方镜像拥有
Official Image
标识点进去后如下图:
tags就是i可用的版本,可以直接通过右边复制命令拉取镜像。
docker常用命令
-
docker pull image:tags
:拉取中央仓库的镜像并下载。若存在多个版本,可以通过:tags
指定版本,不指定将下载最新版本 -
docker images
:查看所有的镜像 -
docker rmi [options] image:tag
:移除镜像options
可选项:-
-f
:对正在运行的容器镜像,强制删除(开发阶段可以这么干,线上不建议)删除时不带-f,若出现如下错误 Error response from daemon: conflict: unable to delete 938b57d64674 (cannot be forced) - image is being used by running container dd02e9d733cb 则说明当前镜像生成的容器正在使用中,需要先删除容器,再删除当前镜像
-
-
docker build [options] PATH | URL | -
:通过Dockerfile创建镜像。Options
:- -f :指定要使用的Dockerfile路径;
-
-m :设置内存最大值;
- -q :安静模式,成功后只输出镜像 ID;
-
--rm :设置镜像成功后删除中间容器;
- --tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
PATH
:上下文路径。是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
-
docker run [options] image [command] [arg...]
:通过镜像创建并运行容器。是docker create
和docker start
命令的结合。可以看到创建并运行了一个容器,但是run命令是前台运行的,页面会进入阻塞状态,如果
ctrl+c
退出tomcat,那么tomcat会停止运行。通过添加
-d
命令后台创建并运行容器。options
:常用选项-
-d
:容器后台运行 -
--name
:为容器指定名字。如果名字已经存在的话,那么容器会创建失败。 -
-p
:宿主机和docker
容器之间的端口映射,例-p 8000:8080
,我们就可以通过宿主机的8000端口访问容器8080端口端口是访问成功的,建立了连接。拿不到页面报了404。
-
-v
:路径映射,将本地文件挂载到容器的某个目录。-v 本地路径:容器内部路径
-
-e
:通过key=value
设置环境变量。也可以通过--env-file
传递环境变量路径 -
--ip
:声明ip地址 -
--rm
:在容器结束时自动退出容器,另一种方式是手动停止然后删除它。 -
-t
:在容器内分配终端会话,可以与容器进行交互。通常与-i
一起使用,即使是后台运行也会是交互界面保持打开状态。 -
-a
:登陆容器,必须是通过-d
方式创建的容器。
-
-
docker ps
:列出当前运行的容器及相关信息-a
: 列出所有容器的相关信息(包括未运行的) -
docker stop [options] container [contaniner..]
:通过contanier id/container name
停止一个或多个容器。容器id可以通过docker ps -a
查询。options
:-t
:关闭容器的限时,如果超时未能关闭则用kill
强制关闭,默认值10s,这个时间用于容器的自己保存状态
-
docker start [options] container [container...]
:通过contanier id/container name
启动一个或多个容器。options
:-a
:将程序的输出带到终端上-i
:接收终端的输入,和run
命令参数一样
-
docker restart [options] container [container...]
:重启容器options
:-t
:与stop
命令参数一样。关闭容器的限时
-
docker logs [options] container
:查看容器的日志options
:-f
:跟踪日志,实时刷新日志-n
:显示最后多少条。-f, -n
参数与tail
命令参数意义相同-t
:显示时间戳
-
docker exec [options] container command [arg...]`:在已经运行的docker容器中执行命令
参数和
docker run
命令参数意义相同。可以通过docker exec --help
查看支持的参数。常用此命令进入容器内部:
Docker容器内部结构
通过tomcat
容器内部的结构来了解docker容器内部结构。容器内部主要包含三层:linux操作系统、app运行环境、app服务
。
-
linux操作系统
:在前面介绍docker时曾说过,docker是为了将操作系统层给抽离出来,保证容器足够小。但是这里又说容器内包含操作系统?这不是前后矛盾么?docker
是为了抽出操作系统,但是同时docker又拥有一定的虚拟化职能。正是因为docker是介于容器化和虚拟化之间,所以绝大部份容器都会带一个操作系统。但是这个操作系统是一个迷你的操作系统。它所占用的资源非常少,拥有的功能也非常有限。但是对于容器的运行来说,对于资源分配、资源控制等这些操作系统底层的职能,它都可以实现,因此安装一个操作系统是利大于弊的。 -
app运行环境
:容器内的类库
进入容器内部:
docker默认会将相关文件存储在/var/lib/docker
目录下:
镜像存储在image
目录下,容器存放在containers
目录下。
Dockerfile构建镜像
什么是Dockerfile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
注意:标准的Dockerfile文件名称就是Dockerfile,不要添加任何后缀,首字母注意大写
使用Dockerfile定制镜像
写Dockerfile
ubuntu@node01:~$ ls
ubuntu@node01:~$ mkdir dockerfile
ubuntu@node01:~$ cd dockerfile
ubuntu@node01:~/dockerfile$ touch Dockerfile
Dockerfile写入内容:
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
通过Dockerfile构建镜像
通过docker build
命令构建镜像,-t
指定镜像的tag
构建成功后可以通过docker images
查看构建后的镜像
运行自定义构建的镜像
Dockerfile指令详解
-
FORM
:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。 -
RUN
:用于执行后面跟着的命令行命令。有以下两种格式:shell
:RUN ./test.sh arg1 arg2 ...
exec
:RUN ["./test.sh", "arg1", "arg2", ...]
两种方式等价
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos RUN yum -y install wget RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos RUN yum -y install wget \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
-
COPY
:复制指令,从上下文目录中复制文件或者目录到容器里指定路径。COPY <源文件路径...> <目标路径>
-
ADD
:ADD
指令和COPY
的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:ADD
的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。ADD
的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
-
CMD
:类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:CMD
在docker run 时运行。RUN
是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。
CMD
指令指定的程序可被docker run
命令行参数中指定要运行的程序所覆盖。注意:如果 Dockerfile 中如果存在多个
CMD
指令,仅最后一个生效。格式:
CMD <shell 命令> CMD ["<可执行文件或命令>","<param1>","<param2>",...] CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
-
ENTRYPOINT
:类似于CMD
指令,但其不会被docker run
的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT
指令指定的程序。但是, 如果运行
docker run
时使用了--entrypoint
选项,将覆盖ENTRYPOINT
指令指定的程序。优点:在执行
docker run
的时候可以指定ENTRYPOINT
运行所需的参数。注意:如果
Dockerfile
中如果存在多个ENTRYPOINT
指令,仅最后一个生效。格式:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参
-
ENV
:设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。格式:
ENV <key> <value> ENV <key1>=<value1> <key2>=<value2>...
以下示例设置
NODE_VERSION = 7.2.0
, 在后续的指令中可以通过$NODE_VERSION
引用:ENV NODE_VERSION 7.2.0 RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \ && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
-
ARG
:构建参数,与ENV
作用一致。不过作用域不一样。ARG
设置的环境变量仅对Dockerfile
内有效,也就是说只有docker build
的过程中有效,构建好的镜像内不存在此环境变量。构建命令
docker build
中可以用--build-arg <参数名>=<值>
来覆盖。格式:
ARG <参数名>[=<默认值>]
-
VOLUME
:定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
格式:
VOLUME ["<路径1>", "<路径2>"...] VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
-
EXPOSE
:仅仅只是声明端口。作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:
EXPOSE <端口1> [<端口2>...]
-
WORKDIR
:指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
格式:
WORKDIR <工作目录路径>
-
USER
:用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。格式:
USER <用户名>[:<用户组>]
-
HEALTHCHECK
:用于指定某个程序或者指令来监控 docker 容器服务的运行状态。格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令 HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令 HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
-
ONBUILD
:用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。格式:
ONBUILD <其它指令>
-
LABEL
: 用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:LABEL <key>=<value> <key>=<value> <key>=<value> ...
比如我们可以添加镜像的作者:
LABEL org.opencontainers.image.authors="runoob"
Dockerfile两大特性
-
分层:
Dockerfile
每一个指令都是一层,分层进行堆叠。下面的层会在上面层的基础上执行。执行顺序:graph LR A[FROM]-->B[WORKDIR]-->C[ADD]-->D[ENV]-->E[RUN]可以把
from
理解为汉堡最下面的面包片,在这个面包片上添加对应的蔬菜,肉,直到add把这些覆盖上,形成一个完整的汉堡。 -
系统快照:
在分层的基础上,
Dockerfile
执行每一层命令时,都会生成临时容器(系统快照)。临时容器可重用,极大加快了镜像的构建速度以及节省系统资源,比如在部署一个新镜像时,前3步和之前tomcat镜像build都一样,所以只需将第四步add进行重新的临时容器构建
对于构建过的镜像,修改
Dockerfile
后再次构建,只会对修改的部分进行执行,已经执行过的步骤并未修改的话,直接使用缓存的临时容器。
Docker容器间通信
容器在创建时,docker会为每一个容器分配ip地址。容器间通过ip地址是可以互相访问的。创建两个容器:
查看容器分配的ip地址:docker inspect NAME|ID
通过上面命令可以看到tomcat容器的ip地址为:172.17.0.2
,nginx的ip地址为:172.17.0.3
但是在实际使用中,服务间并不会通过ip地址去访问,而是通过配置host
,通过host映射ip去访问。
可以看到,容器并不知道tomcat是什么,那么容器内如何实现host
配置的效果?
容器间单向通信link
创建容器时通过--link
参数,关联容器名:
root@node01:/var/lib/docker# docker run -d --name nginx2 -p 8003:80 --link tomcat nginx
容器间双向通信bridge
通过--link
只能单向的配置一个容器访问另一个容器,如果想要双方都能互通需要两个容器互相--link
。这配置很不方便,而且实际使用中不可能只有两台容器间互相访问,如果容器数量大的话,这种配置方式也是反人类操作。因此还有一种更优雅的方式配置多容器间通信——bridge
。
何为网桥
见上图,docker是部署在宿主机上的,docker内容器自己会组成一个局域网,拥有自己的ip,可以将docker带入虚拟机理解。如果宿主机想要访问docker
内的容器,那么首先宿主机应该是与宿主机的网络是互通的。宿主机会有一个虚拟网卡,ip地址为容器内局域网的ip地址:
这个虚拟网卡就是容器内部网络的网关。当容器内服务想要访问外部网络,例如:百度时,首先会跳转到网关,然后由网关转发到物理网卡,在有物理网卡出去访问外部网络。这里的网关就是网桥。
如何配置网桥
通过docker network ls
可以查看当前docker创建的网桥。
上面NAME
为bridge
的就是一个网桥,网桥信息如下。
可以通过docker network create -d bridge <bridge-name>
创建一个网桥:
查看网桥信息:
查看宿主机ip信息:
可以看到多了一块虚拟网卡,ip与网桥配置ip相同。
容器与网桥的绑定
网桥配置好后,容器就需要与网桥绑定了,有两种绑定方式:
-
创建容器时绑定:
docker run -d --name <容器名> --network <网桥名> [...其他参数] image:tags command
。 -
通过
connnect
命令绑定:docker network connect <网桥名> <容器名>
网桥工作原理
其实前面介绍网桥时就已经大概介绍了工作原理了。不熟悉的话可以看一下之前写的另一篇文章集群负载均衡,在网络部分详细讲了下一跳的机制。
而网桥的工作原理与此类似。所有的容器都与网桥绑定,因此网桥知道每一个容器的ip地址。所有容器想要访问其他容器时,先将请求打到网桥这里,由网桥将请求转发到目标容器。
容器间数据共享
通过在宿主机开辟一块空间,所有容器共享这块空间。可以通过volume
设置。两种方式:
docker run -v <宿主机路径:容器内挂载路径> ...
:创建容器时指定挂载路径。docker run --volumes-from <容器名> ....
:从已创建的挂载容器获取挂载信息并创建新的容器。相比于第一种方式,只需要指定一次挂载路径,其他容器都从第一个容器复制信息。当容器数量较大时/路径较复杂时避免重复写路径出现写错路径的风险。