Docker简介
什么是Docker
Docker是一个开源项目,诞生于2013年初,最初是dotCloud公司内部的一个业余项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会,遵从了Apache2.0协议,项目代码在GitHub上进行维护。Docker自开源后受到广范的关注和讨论,以至于dotCloud公司后来都改名为Docker Inc。RedHat已经在其RHEL6.5中集中支持Docker;Google也在其PaaS产品中广泛应用。Docker的目标是实现经量级的操作系统虚拟化解决方案。Docker的基础是Linux容器(LXC)等技术。在LXC的基础上Docker进行了进一步的封装,让用户不需要关心容器的管理,使得操作更加简单。用户操作Docker的容器就像操作一个快速轻量级的虚拟机一样简单。
下图比较了Docker和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现的虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层现实现
Docker的设计思想
Docker的思想来自于集装箱,集装箱解决了什么问题?在一艘大船上,可以把货物规整的摆放起来。并且各种各样的货物被集装箱标准化了,集装箱和集装箱之间不会互相影响。那么我就不需要专门运送水果的船和专门运送化学品的船了。只要这些货物在集装箱里封装的好好的,那我就可以用一艘大船把他们都运走。docker就是类似的理念。现在都流行云计算了,云计算就好比大货轮。docker就是集装箱。
- 不同的应用程序可能会有不同的应用环境,比如.net开发的网站和php开发的网站依赖的软件就不一样,如果把他们依赖的软件都安装在一个服务器上就要调试很久,而且很麻烦,还会造成一些冲突。比如IIS和Apache访问端口冲突。这个时候你就要隔离.net开发的网站和php开发的网站。常规来讲,我们可以在服务器上创建不同的虚拟机在不同的虚拟机上放置不同的应用,但是虚拟机开销比较高。docker可以实现虚拟机隔离应用环境的功能,并且开销比虚拟机小,小就意味着省钱了。
- 你开发软件的时候用的是Ubuntu,但是运维管理的都是centos,运维在把你的软件从开发环境转移到生产环境的时候就会遇到一些Ubuntu转centos的问题,比如:有个特殊版本的数据库,只有Ubuntu支持,centos不支持,在转移的过程当中运维就得想办法解决这样的问题。这时候要是有docker你就可以把开发环境直接封装转移给运维,运维直接部署你给他的docker就可以了。而且部署速度快。
- 在服务器负载方面,如果你单独开一个虚拟机,那么虚拟机会占用空闲内存的,docker部署的话,这些内存就会利用起来。
总之docker就是集装箱原理。
为什么要使用Docker
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个Docker 容器。
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。
传统虚拟机方式运行10 个不同的应用就要起10 个虚拟机,而Docker 只需要启动10 个隔离的应用即可。具体说来,Docker 在如下几个方面具有较大的优势。
Docker底层原理
Docker是如何工作的
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们前面说到的集装箱。
Docker run了啥
什么是容器
容器镜像是一个软件的轻量级独立可执行软件包,包含运行它所需的一切:代码,运行时,系统工具,系统库,设置。不管环境如何,集装箱化软件都可以运行相同的Linux和Windows应用程序。容器将软件与其周围环境隔离开来,例如开发环境和生产环境之间的差异,并有助于减少在同一基础架构上运行不同软件的团队之间的冲突。
- 轻量级;在一台机器上运行的Docker容器共享该机器的操作系统内核; 他们立即开始并使用更少的计算和内存。图像由文件系统层构建并共享公用文件。这最大限度地减少了磁盘使用量,图像下载速度更快。
- 标准;Docker容器基于开放标准,可在所有主要Linux发行版,Microsoft Windows以及任何基础架构(包括虚拟机,裸机和云中)上运行。
- 安全;Docker容器将应用程序彼此隔离并从底层基础架构中分离出来。Docker提供了最强大的默认隔离功能,可以将应用程序问题限制在一个容器中,而不是整个机器上。
Docker安装
Docker 的基本组成
镜像(Image)
Docker镜像就好比是一个模板,可以通过这个模板来创建容器服务器,tomcat ===> run ===> tomcat01容器(提供服务者),通过这个镜像可以创建多个容器。
容器(Containers)
Docker利用容器技术,独立运行一个或者一组应用,通过镜像来完成。
启动、停止、删除基本命令。
Docker 下载
CentOS Docker 安装
Docker支持以下的CentOS版本:
CentOS 7 (64-bit)
CentOS 6.5 (64-bit) 或更高的版本
前提条件
目前,CentOS 仅发行版本中的内核支持 Docker。
Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。
Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位、系统内核版本为 2.6.32-431 或者更高版本。
安装帮助
#卸载旧的版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
#安装方法
yum install docker
#启动docker
systemctl start docker
systemctl enable docker #开机自启
#查看版本
docker version
阿里云容器镜像服务加速
针对Docker客户端版本大于 1.10.0 的用户
可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://mkmwiqx8.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
测试运行 hello-world
docker run hello-world
由于本地没有hello-world这个镜像,所以会下载一个hello-world的镜像,并在容器内运行。
测试运行Tomcat
#将8080端口映射为80,或者8080:8080还是原先的8080端口,不可以不写。
docker run -d -p 80:8080 tomcat:8.5
Tomcat默认镜像有个坑
Tomcat目录下的webapps默认为空的,webapps.dist才是正常初始化webapps的内容
Docker常用命令
帮助命令
#查看docker版本
docker version
#显示全系统信息
docker info
#显示docker相关的所有命令及功能说明
docker --help
镜像命令
docker images列表本机上的镜像
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/tomcat 8.5 37bdd9cb0d0e 5 weeks ago 533 MB
docker.io/tomcat latest 040bdb29ab37 5 weeks ago 649 MB
docker.io/centos latest 300e315adb2f 2 months ago 209 MB
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
可选项
-a 列表本地的所有镜像及子镜像
-q 只显示镜像ID
--digests 显示镜像的摘要信息
--no-trunc 显示完整的镜像信息
docker search 镜像搜索命令
搜索网站:https://hub.docker.com
语法
docker search 镜像名称
docker search 镜像名称 -[options] 说明
-s 列出收藏数不少于指定值的镜像
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker search -s 3000 mysql
docker pull 镜像下载命令
docker pull 镜像名称:[TAG]
例如
- docker pull tomcat:8.5 下载8.5的镜像版本
- dokcer pull tomcat 默认下载最新的tomcat镜像版本 【latest】
docker rim 镜像删除命令
根据镜像ID删除
docker rmi [Image ID]
批量删除镜像
docker rmi [Image ID 1] [Image ID 2]...
全部删除镜像
docker rmi -f $(docker images -aq)
容器命令
创建并启动容器
docker run [options] images [command][args] /镜像ID
有些是一个减号,有些是两个减号
--name="容器新名字": 为容器指定一个名称;
-d: 后台运行容器,并返回容器ID,也即启动守护式容器;
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P: 随机端口映射;
-p: 指定端口映射,有以下四种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
交互式运行
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -it centos /bin/bash
[root@1c25e3c39dd9 /]#
直接进入了容器
退出容器
#退出容器并关闭容器
exit
#退出不关闭容器
ctrl+p+q
列表容器
#默认只列出正在运行的容器
docker ps [options]
options 的参数说明
-a 显示所有运行和没有运行的容器
-l :显示最近创建的容器。
-n:显示最近n个创建的容器。
-q :静默模式,只显示容器编号。
--no-trunc :不截断输出。
启动重启关闭容器
#重启
docker restart 容器ID或容器名称
#启动
docker start 容器ID或容器名称
#停止
docker stop 容器ID或容器名称
#强制停止
docker kill 容器ID或容器名称
删除容器
#删除指定的容器,不能删除正在运行的容器,强制删除 rm -f
docker rm 容器ID
#全部删除
docker rm -f $(docker ps -aq)
其它常用命令
后台启动容器
#命令 docker run -d 镜像名
docker run -d centos
查看日志
#命令 docker logs -tf --tail -f 容器ID
docker logs -tf --tail -f cee12a8be7ab
-t 是加入时间戳
-f 跟随最新的日志打印
--tail 数字 显示最后多少条
查看容器运行进程
docker top 容器ID
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker top cee12a8be7ab
进入正在进行的容器
- 方式1
#重新打开一个新的终端 如果以这种方式进入容器,可以使用exit退出。而不会关闭容器
docker exec -it 容器ID /bin/bash
- 方式2
docker attach 容器ID
两种方式的区别
exec 在容器中打开新的终端 并且可以启动新的进程
attach 直接进行容器终端,不会启动新的进程
这种方式里面使用exit退出会关闭容器 如果不想关闭容器必须使用ctrl+p+q
查询容器内部细节
docker inspect 容器ID
容器与主机文件拷贝
#从容器拷贝文件到主机目录
docker cp 容器ID:容器内的路径 主机目录
#从主机目录拷贝文件到容器
docker cp 主机目录 容器ID:容器内的路径
Docker命令总结
Docker镜像详解
什么是镜像
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/centos latest 300e315adb2f 2 months ago 209 MB
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
分层结构
问什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是 - 共享资源。
比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。
这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
答案是不会!
修改会被限制在单个容器内。
这就是我们接下来要说的容器 Copy-on-Write 特性。
- 新数据会直接存放在最上面的容器层。
- 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
- 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。
可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
典型的Linux在启动后,首先将 rootfs 置为 readonly, 进行一系列检查, 然后将其切换为 “readwrite” 供用户使用。在docker中,起初也是将 rootfs 以readonly方式加载并检查,然而接下来利用 union mount 的将一个 readwrite 文件系统挂载在 readonly 的rootfs之上,并且允许再次将下层的 file system设定为readonly 并且向上叠加, 这样一组readonly和一个writeable的结构构成一个container的运行目录, 每一个被称作一个Layer。如下图所示。
下面我们深入讨论容器层的细节。
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
- 添加文件: 在容器中创建文件时,新文件被添加到容器层中。
- 读取文件: 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。
- 修改文件: 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
- 删除文件: 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
Commit镜像
#docker commit 提交一个容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" [容器ID] 目标镜像名:[TAG]
Docker容器数据卷
什么是容器数据卷
数据卷就是数据(一个文件或者文件夹)。数据卷是特殊的目录,可以绕过联合文件系统,为一个或多个容器提供访问。
数据卷设计的目的是数据的永久化,是完全独立于容器的生命周期,不会在容器删除时删除其挂载的数据卷,也不会存在类似垃圾收集机制,对容器引用的数据卷进行处理。
在docker的使用过程中,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,所以这就涉及到Docker容器的数据操作。 容器中数据管理主要有两种方式:数据卷和数据卷容器。
数据卷存在于宿主机中,独立于容器,和容器的生命周期是分离的,数据卷存在于宿主机的文件系统中,数据卷可以目录也可以是文件,容器可以利用数据卷与宿主机进行数据共享,实现了容器间的数据共享和交换。
容器数据卷的特征:
- 数据卷在容器服务启动时初始化,如果容器使用的镜像在挂载点包含了数据,这些数据会拷贝到新初始化的数据卷中。
- 数据卷可以在容器之间共享和重用,数据卷是宿主机中的一个目录,与容器生命周期隔离。
- 可以对数据卷里的内容直接修改,修改回马上生效,无论是容器内操作还是本地操作。
- 对数据卷的更新不会影响镜像的更新,数据卷是独立于联合文件系统,镜像是基于联合文件系统。镜像与数据卷之间不会有相互影响。
- 数据卷会一直存在,即使挂载数据卷的容器已经被删除。
数据卷使用
直接使用命令添加
docker run -it -v /宿主机目录:/容器内目录 centos /bin/bash
#起来之后通过docker inspect [容器ID] 查看容器卷是否挂载成功
测试发现宿主机与容器文件是双向绑定的。如果容器停止了,修改宿主机目录容器也会发生变化
实战:安装MySQL
#安装
docker pull mysql:5.7
#启动
-d 后台启动
-p 端口
-v 挂载数据卷
-e 环境配置
docker run -d -p 3306:3306 -v /root/docker/mysql/conf:/etc/mysql/conf.d -v /root/docker/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
#使用客户端测试连接
- 新建一个数据库
- 发现宿主机目录多了test数据库
具名与匿名挂载
# 匿名挂载
-v 容器内路径
# 安装nginx匿名挂载
docker run -d -P -v /etc/nginx nginx
# 查看所有卷列表,这里发现,这种就是匿名挂载,只写了容器内路径,没有容器外路径,名称是自动生成
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker volume ls
DRIVER VOLUME NAME
local f8fdde74566dd2315b65a504eb5b64097886a5a5621b755a089c85b5849b3013
# 具名挂载
docker run -dP -v juming-nginx:/etc/nginx nginx
# 查看所有卷列表,这里发现,名称是我们命令指定的
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker volume ls
DRIVER VOLUME NAME
local juming-nginx
# 查看卷详情,发现为指定宿主机目录时默认目录为:/var/lib/docker/volumes/[VOLUME NAME]/_data
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker volume inspect juming-nginx
[
{
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": {},
"Scope": "local"
}
]
#如何确定是具名还是匿名或者指定路径
-v 卷名:容器路径 #具名挂载
-v 容器路径 #匿名挂载
-v 宿主机路径:容器路径 #指定路径挂载
拓展
# 通过 -v 容器内路径,ro rw改变读写权限
ro readonly #只读
rw readwrite #读写
# 一旦设定权限,就会限定容器内的操作权限
docker run -dP -v juming-nginx:/etc/nginx:ro nginx
docker run -dP -v juming-nginx:/etc/nginx:rw nginx
数据卷容器
#通过--volumes-from实现容器间的数据共享
docker run -it --name centos2 --volumes-from [指向同步的容器] [镜像] /bin/bash
结论
容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦持久化到本地,这个时候,本地的数据不会删除的!
Dockerfile
构建步骤
- 编写一个dockerfile文件
- docker build构建为一个镜像
- docker run镜像
- docker push发布镜像(DockerHub或者阿里云镜像仓库)
Dockerfile构建过程
基础知识
- 每个保留关键字(指令)都必须大写
- 指令从上到下执行
- #表示注释
- 每个指令都会创建提交一个镜像层
关键字
FROM #基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER #镜像维护者的姓名混合邮箱地址
RUN #容器构建时需要运行的命令
EXPOSE #当前容器对外保留出的口
WORKDIR #指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV #用来在构建镜像过程中设置环境变量
ADD #将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY #类似ADD,拷贝文件和目录到镜像中!
VOLUME #容器数据卷,用于数据保存和持久化工作
CMD #指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效!
ENTRYPOINT #指定一个容器启动时要运行的命令!和CMD一样
ONBUILD #当构建一个被继承的DockerFile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发
实战测试
构建一个自己的Centos
vim dockerfile
# 1 编写dockerfile文件
FROM centos:7
MAINTAINER liao<xxxx@xx.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 8080
CMD echo $MYPATH
CMD echo "-------end--------"
CMD /bin/bash
# 2 build构建镜像
docker build -f dockerfile -t mycentos:1 .
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1 91b851687dc7 35 seconds ago 460 MB
#运行发现进入可dockerfile配置的工作路径
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -it mycentos:1
[root@cc2497166c7b local]#
#查看镜像历史
docker history mycentos:1
CMD和ENTRYPOINT
CMD #指定一个容器启动时要运行的命令,dockerFile中可以有多个CMD指令,但只有最后一个生效!
ENTRYPOINT #指定一个容器启动时要运行的命令!和CMD一样
测试CMD
#编写dockerfile
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# vim docker-cmd-test
FROM centos:7
CMD ["ls","-a"]
#构建镜像
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker build -f docker-cmd-test -t testcmd:1 .
#运行镜像,发现ls -a命令生效
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -it testcmd:1
. .. .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@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -it testcmd:1 -l
/usr/bin/docker-current: Error response from daemon: oci runtime error: container_linux.go:235: starting container process caused "exec: \"-l\": executable file not found in $PATH".
#cmd的清理下 -l替换了CMD ["ls","-a"]命令,由于-l不是命令所有无法执行
测试ENTRYPOINT
#编写dockerfile
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# vim docker-test-ENTRYPOIN
FROM centos:7
ENTRYPOINT ["ls","-a"]
#构建镜像
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker build -f docker-test-ENTRYPOINT -t testentrypoint:1 .
#运行镜像
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -it testentrypoint:1
. .dockerenv bin etc lib media opt root sbin sys usr
.. anaconda-post.log dev home lib64 mnt proc run srv tmp var
#运行镜像 加 -a 发现可以运行,与cmd不一样
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -it testentrypoint:1 -a
. .dockerenv bin etc lib media opt root sbin sys usr
.. anaconda-post.log dev home lib64 mnt proc run srv tmp var
实战:Tomcat
#编写dockerfile
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# vim dockerfile
FROM centos:7
MAINTAINER liao<xxxxx@xx.com>
ADD jdk-8u281-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.43.tar.gz /usr/local/
RUN yum install -y vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_281
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.43
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.43
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD $CATALINA_BASE/bin/startup.sh && tail -f $CATALINA_BASE/logs/catalina.out
#构建镜像
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker build -t mytomcat:1 .
#运行容器
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -d -p 8080:8080 -v /root/tomcat/webapps:/usr/local/apache-tomcat-9.0.43/webapps -v /root/tomcat/logs:/usr/local/apache-tomcat-9.0.43/logs --name mytomcat1 mytomcat:1
#访问Tomcat OK,部署成功!
发布镜像
DockerHub
- DokcerHub官网注册https://registry.hub.docker.com/
- 服务器上提交镜像
#服务器登陆DockerHub账号
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker login -u [DockerHub账号]
Password:
Login Succeeded
#Push 发布镜像,本地的镜像名需要加上镜像版本号
docker push [DockerHub账号]/tomcat:9
#未带上镜像版本号
docker tag [ImageId] [DockerHub账号]:[镜像版本号]
阿里云镜像服务
- 登陆阿里云,进入容器镜像服务创建命名空间
- 创建镜像仓库
- 进入仓库,查看操作指南
Docker网络
理解Docker0
测试
三个网络
docker是如何处理容器之间的网络访问?
#查看容器内的内部网络地址 ip addr
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker exec -it cbd45f7a4344 ip addr
操作系统可以ping通docker容器内部IP
原理
- 我们启动每一个docker容器,docker就会给容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是evth-pair技术!
#再次测试 ip addr,多了
我们发现容器带来的网卡都是成对的
evth-pair 就是一对虚拟的设备接口,它们都是成对出现的,一端连着协议,一端彼此相连
正因为此特性,evth-pair 充当了一个桥梁,连接各种虚拟网络设备
所以docker容器之间网络是互通的
Docker中的所有网络接口都是虚拟的。
–link
#直接ping容器无法ping通
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known
#使用--link解决两个容器名称连通(但是这样的反向无法ping通)
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker run -dP --name tomcat02 --link tomcat01 tomcat:latest
#通过查看tomcat02配置可看出: 它是在hosts文件添加了映射
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker exec -it tomcat02 cat /etc/hosts
172.17.0.2 tomcat01 0200a127f13e
现在已经不建议使用了!
自定义网络
#查看所有的docker网络
docker network ls
网络模式
- bridge:桥接 docker默认
- none:不配置网络
- host:和宿主机共享网络
- container:容器网络连通
测试
#我们直接启动的命令, --net bridge 就是我们的docker0
docker run -dP tomcat
docker run -dP --net bridge tomcat
#docker0特点,默认,域名不能访问,--link可以打通
#自定义一个网络
# --driver bridge 桥接
# --subnet 子网
# --gateway 网关
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 运行Tomcat
docker run -dP --name tomcat1 --net mynet tomcat:9
docker run -dP --name tomcat2 --net mynet tomcat:9
# 使用自定义网络可以使用名称ping通了
[root@iZ2zea2hmy4kqdhv4tdmn3Z ~]# docker exec -it tomcat1 ping tomcat2
网络连通
#这两个网络是在不同网段,正常是无法连通的
ip addr
#无法连通
[root@VM-8-11-centos ~]# docker exec -it tomcat1 ping tomcat2
ping: tomcat2: Name or service not known
#使用connect命令连通容器与网络
[root@VM-8-11-centos ~]# docker network connect demo_net tomcat1
#再次尝试,可以ping通
[root@VM-8-11-centos ~]# docker exec -it tomcat1 ping tomcat2
PING tomcat2 (192.168.1.2) 56(84) bytes of data.
64 bytes from tomcat2.demo_net (192.168.1.2): icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from tomcat2.demo_net (192.168.1.2): icmp_seq=2 ttl=64 time=0.051 ms