解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
环境配置如此麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。
Docker是基于Go语言实现的云开源项目。
Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。
Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。将应用运行在 Docker 容器上面,而 Docker 容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作
虚拟机(virtual machine)就是带环境安装的一种解决方案。
虚拟机的缺点:资源占用多,冗余步骤多,启动慢
由于前面虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。
比较了 Docker 和传统虚拟化方式的不同之处:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
Docker 利用 容器(Container) 独立运行的一个或一组应用。容器是用镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。
仓库(Repository) 是集中存放镜像文件的场所。
仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云 等
官方文档
中文官方文档
yum install -y epel-release
Docker使用EPEL发布,RHEL系的OS首先要确保已经持有EPEL仓库,否则先检查OS的版本,然后安装相应的EPEL包。
开始安装:yum install -y docker-io
安装后的配置文件位置:/etc/sysconfig/docker
启动Docker后台服务:service docker start
验证Docker版本: docker version
如果您不是root用户,请在命令前面加上
sudo
yum remove docker \
docker-common \
docker-selinux \
docker-engine
如果 yum 报告未安装任何这些软件包,这表示情况正常。
yum -y install gcc
yum -y install gcc-c++
yum install -y yum-utils device-mapper-persistent-data lvm2
注意,官方文档中提供的镜像地址可能依旧访问缓慢,所以需要用到阿里云的镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新 yum 软件包索引 :yum makecache fast
安装最新版本的 Docker CE: yum install docker-ce
或者安装特定版本:
启动Docker: systemctl start docker
HelloWorld: docker run hello-world
,通过运行hello-world ,Docker先检查本地是不是要此镜像,没有自动从仓库中拉取并运行。
如果加载慢,请看下面的教程,配置镜像加速器
官方说明
通过 Docker 官方镜像加速,中国区用户能够快速访问最流行的 Docker 镜像。该镜像托管于中国大陆,本地用户现在将会享受到更快的下载速度和更强的稳定性,从而能够更敏捷地开发和交付 Docker 化应用。
Docker 中国官方镜像加速可通过 registry.docker-cn.com 访问。该镜像库只包含流行的公有镜像。私有镜像仍需要从美国镜像库中拉取。
您可以使用以下命令直接从该镜像加速地址进行拉取:
docker pull registry.docker-cn.com/myname/myrepo:mytag
例如:
docker pull registry.docker-cn.com/library/ubuntu:16.04
注: 除非您修改了 Docker 守护进程的
--registry-mirror
参数 (见下文), 否则您将需要完整地指定官方镜像的名称。例如,library/ubuntu、library/redis、library/nginx。
您可以配置 Docker 守护进程默认使用 Docker 官方镜像加速。这样您可以默认通过官方镜像加速拉取镜像,而无需在每次拉取时指定 registry.docker-cn.com
。
您可以在 Docker 守护进程启动时传入 --registry-mirror
参数:
docker --registry-mirror=https://registry.docker-cn.com daemon
为了永久性保留更改,您可以修改 /etc/docker/daemon.json
文件并添加上 registry-mirrors 键值。
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
修改保存后重启 Docker 以使配置生效:systemctl restart docker
注: 您也可以使用适用于 Mac 的 Docker 和适用于 Windows 的 Docker 来进行设置。
鉴于国内网络问题,后续拉取 Docker 镜像十分缓慢,我们可以需要配置加速器来解决,我使用的是阿里云的本人自己账号的镜像地址(需要自己注册有一个属于你自己的加速器地址)
注册一个阿里云账户(可用淘宝账号):https://dev.aliyun.com/search.html
创建一个获得加速器地址链接:https://cr.console.aliyun.com/cn-hangzhou/mirrors
配置 CentOS6.8 本机Docker运行镜像加速器
CentOS7 配置镜像加速器:针对Docker客户端版本大于 1.10.0 的用户您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
systemctl daemon-reload
systemctl restart docker
完成配置!!
CentOS6:使用chkconfig命令即可。
开启服务:service docker start
开机自启:chkconfig docker on
禁用自启: chkconfig docker off
CentOS7:使用systemctl中的enable、disable 即可
开启服务:systemctl start docker
开机自启:systemctl enable docker
禁用自启:systemctl disable docker
Docker帮助命令: docker --help
Docker 详细命令:docker COMMAND --help
查看版本:docker version
Docker统计信息:docker info
注意:Docker命令中 IMAGE
可以指代 REPOSITORY
、 IMAGE ID
、 REPOSITORY:TAG
同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG
来定义不同的镜像。如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest
镜像
手动从Docker镜像仓库中搜索:Docker Hub
命令:docker search [OPTIONS] 镜像名字
命令:docker pull 镜像名字[:TAG]
示例:
下载镜像:docker pull tomat
,等价于 docker pull tomat:latest
下载指定版本:docker pull tomcat:7.0
需要查询镜像的版本/TAG,转到 Docker Hub 搜索
命令:docker rmi [OPTIONS] IMAGE [IMAGE...]
示例:
强制删除镜像:docker rmi -f hello-world
删除多个镜像 docker rmi hello-world nginx:latest
删除所有镜像:docker rmi -f $(docker images -qa)
,其实就是在子命令里面检索出所有的镜像ID,再执行删除
有镜像才能创建容器,这是根本前提(下载一个CentOS镜像演示) :docker pull centos
命令:docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS说明(常用):有些是一个减号,有些是两个减号
–name=“容器新名字” : 为容器指定一个名称
-d : 后台运行容器,并返回容器ID,也即启动守护式容器;
-i
:以交互模式运行容器,通常与 -t 同时使用
-t
:为容器重新分配一个伪输入终端,通常与 -i 同时使用
-P : 随机端口映射
-p : 指定端口映射,有以下四种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
示例:
启动tomcat:docker run -it -p 8888:8080 tomcat
:表示将主机的8888端口映射到容器的8080,使得可以通过8888端口访问到容器。即可以通过链接:主机IP:8888
访问到tomcat
注意需要开放相应的端口才能其它主机访问
使用交互模式运行容器centos
docker run -it centos
ps -ef
执行命令的id与运行容器的id一致,说明就是在容器centos中
命令:docker ps [OPTIONS]
-q
:静默模式,只显示容器编号。示例:
显示最近创建的容器:docker ps -l
显示最近3个创建的容器:docker ps -n 3
注意:Docker命令中 CONTAINER
可以指代 CONTAINER ID
、 NAMES
当登录到Docker容器中时,使用命令 exit
退出并停止容器
另外一个退出方式:快捷键 ctrl+P+Q
可以使容器不停止退出
如果快捷键无效,请检查热键是否被占用
命令:docker start [OPTIONS] CONTAINER [CONTAINER...]
命令:docker restart [OPTIONS] CONTAINER [CONTAINER...]
示例:docker restart 容器ID或者容器名
命令:docker stop [OPTIONS] CONTAINER [CONTAINER...]
示例:docker stop 容器ID或者容器名
命令:docker kill [OPTIONS] CONTAINER [CONTAINER...]
示例:docker kill 容器ID或者容器名
命令:docker rm [OPTIONS] CONTAINER [CONTAINER...]
示例:
删除单个容器:docker rm 容器ID
删除多个容器:docker rm -f $(docker ps -a -q)
删除多个容器2:docker ps -a -q | xargs docker rm
:将查询的结果赋值给xargs
继于上面的启动容器,使用它的一个参数 -d
即可设置成守护模式
命令:docker run -d 容器名
使用镜像 centos:latest
以后台模式启动一个容器
示例:docker run -d centos
【错误示例】
问题 :通过 docker ps -a
会发现容器已经退出!
很重要的一点:要想Docker容器后台运行,就必须有一个前台进程
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如 service nginx start
,但是这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,会立即自杀因为他觉得他没事可做了。所以最佳的解决方案是:将你要运行的程序以前台进程的形式运行:docker run -it centos
命令:docker logs [OPTIONS] CONTAINER
示例:
显示容器日志:docker logs 容器ID/名称
动态显示容器日志:
运行容器并执行shell脚本,使其处于非空闲状态,不至于自杀进程:
docker run -d centos /bin/sh -c "while true;do echo hello docker;sleep 2;done"
查看日志:要求显示最新三条日志、显示时间戳、跟踪日志输出
docker logs --tail 3 -t -f 13617502c43e
命令:docker top CONTAINER [ps OPTIONS]
命令:docker inspect [OPTIONS] NAME|ID [NAME|ID...]
示例:
查看与物理主机的挂载目录:docker inspect --format "{{.Mounts}}" 容器ID
命令:docker attach [OPTIONS] CONTAINER
示例:
重新进入容器:docker attach 容器ID
命令:docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
示例:docker exec 13617502c43e ls -l
:相当于在容器中执行了 ls -l
命令又返回到本机
那么 attach 和 exec 有什么区别呢?
就是说 attach命令会进入到容器中,而 exec 可以不进入容器,直接就可以执行命令并且将结果显示出来。
同时 以下两条命令都表示进入容器中
docker attach 容器ID
docker exec -t 容器ID /bin/bash
命令:
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
示例:
docker cp 容器ID:容器内路径 目的主机路径
:docker cp d641bbb4438b:/usr/test.txt ./
docker cp 目的主机路径 容器ID:容器内路径
:docker cp ./test.txt d641bbb4438b:/
Docker镜像是一种 UnionFS(联合文件系统)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。
Union 文件系统是 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??
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载
为什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是 共享资源
比如:有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
Docker镜像都是只读的。当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
根据容器的更改创建新映像,使用 docker commit 提交容器副本 使之成为一个新的镜像
命令:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
示例:
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
docker commit -a "theliang" -m "del tomcat docs" 155a8af163cf atguigu/tomcat01:1.2
通过命令 docker images
就可以看到刚刚自己创建的镜像
先来看看Docker的理念:
Docker容器产生的数据,如果不通过docker commit 成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。为了能保存数据在docker中我们使用卷。
类似Redis里面的rdb和aof文件
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
特点:
命令:docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
示例:docker run -it -v /myDataVolume:/dataVolumeContainer centos
表示:将宿主机根目录下下myDataVolume文件夹与容器内根目录下dataVolumeContainer目录相联系(运行命令后会自动创建文件夹)
其它查看方式:docker inspect --format "{{.Config.Volumes}}" 容器ID
此处显示的信息只有docker 容器本地数据卷的信息,与其关联的物理主机的挂载目录位置信息,要使用如下信息查看:
docker inspect -f "{{.Mounts}}" 容器ID
也通过使用grep显示:docker inspect 容器ID | grep Mounts -A 10
示例:带权限命令:
docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
这里多加了一个 :ro
即 read only ,表示容器只有只读权限,无法对文件修改。
作用:从Dockerfile构建一个映像
命令:docker build [OPTIONS] PATH | URL | -
name:tag
出于可移植和分享的考虑,用 -v 主机目录:容器目录
这种方法不能够直接在 Dockerfile 中实现。
由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录。
示例:根据镜像centos,添加两个数据卷(包装了一层),生成新的镜像
# volume test
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContaioner2"]
CMD ECHO "finished,----------success1"
CMD /bin/bash
注意命令中有一个点,表示当前位置
通过上述步骤,容器内的卷目录地址已经知道,但是对应的主机目录地址在哪?
解决:可以通过 inspect 查看容器细节,详细操作在 inspect示例、直接添加数据卷示例
中给出
备注:Docker挂载主机目录Docker访问出现
cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true
参数即可
docker run -it -v /myDataVolume:/dataVolumeContainer --privileged=true centos
命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器
换言之,活动硬盘上挂载活动硬盘,实现数据的传递依赖。
命令:dockeer run -it --name 子容器ID --volumes-from 父容器ID 容器名
示例:要创建数据卷容器
先创建一个父容器,我们可以用上面示例中创建出来的 liang/centos
作为模板:
docker run -it --name dc01 theliang/centos
创建子容器(dc02 和 dc03),继承自dc01
docker run -it --name dc02 --volumes-from dc01 liang/centos
此时,dc01容器中的两个数据卷就可以被它的子容器共享了,它们之间通过数据卷可以共享数据
注意点:
总结:容器之间配置信息的传递,数据卷的生命周期一直持续到时没有容器使用它为止。
docker 目前支持以下 5 种网络模式:
docker run 创建 Docker 容器时,可以用 -net 选项指定容器的网络模式。
-net=host
指定。与宿主机共享网络,此时容器没有使用网络的 namespace,宿主机的所有设备,如 Dbus 会暴露到容器中,因此存在安全隐患。-net=container:NAME_or_ID
指定。指定与某个容器实例共享网络。-net=none
指定。不设置网络,相当于容器内没有配置网卡,用户可以手动配置。-net=bridge
指定,默认设置。此时 docker 引擎会创建一个 veth 对,一端连接到容器实例并命名为 eth0,另一端连接到指定的网桥中(比如 docker0),因此同在一个主机的容器实例由于连接在同一个网桥中,它们能够互相通信。容器创建时还会自动创建一条 SNAT 规则,用于容器与外部通信时。如果用户使用了 -p 或者 -Pe 端口,还会创建对应的端口映射规则。docker network create
创建,并且默认支持多种网络驱动,用户可以自由创建桥接网络或者 overlay 网络。默认是桥接模式,网络地址为 172.17.0.0/16,同一主机的容器实例能够通信,但不能跨主机通信。
如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
这个模式和前两个不同。在这种模式下,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。
bridge 模式是 Docker 默认的网络设置,此模式会为每一个容器分配 Network Namespace、设置 IP 等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。
当 Docker server 启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
接下来就要为容器分配 IP 了,Docker 会从 RFC1918 所定义的私有 IP 网段中,选择一个和宿主机不同的 IP 地址和子网分配给 docker0,连接到 docker0 的容器就从这个子网中选择一个未占用的 IP 使用。如一般 Docker 会使用 172.17.0.0/16 这个网段,并将 172.17.42.1/16 分配给 docker0 网桥(在主机上使用 ifconfig 命令是可以看到 docker0 的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
这里同主机不同容器之间通信主要使用 Docker 桥接(Bridge)模式。该 bridge 接口在本地一个单独的 Docker 宿主机上运行,并且它是我们后面提到的所有三种连接方式的背后机制。
$ ifconfig docker0
docker0 Link encap:Ethernet HWaddr 56:84:7a:fe:97:99
inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# 查看容器的内部IP
$ docker inspect --format='{{.NetworkSettings.IPAddress}}' $CONTAINER_ID
# Elasticsearch容器
$ docker inspect --format='{{.NetworkSettings.IPAddress}}' 4d5e7a1058de
172.17.0.2
# Kibana容器
$ docker inspect --format='{{.NetworkSettings.IPAddress}}' 4f26e64bfe82
172.17.0.4
方式一:使用容器的 IP 地址来通信
# 进入Kibana容器
$ docker exec -it 4f26e64bfe82 /bin/bash
# 在Kibana容器使用ES容器的IP地址来访问ES服务
$ curl -XGET 'http://172.17.0.2:9200/_cat/health?pretty'
1493707223 06:40:23 ben-es yellow 1 1 11 11 0 0 11 0 - 50.0%
方式二:使用宿主机的 IP 加上容器暴露出的端口号来通信
# 进入Kibana容器
$ docker exec -it 4f26e64bfe82 /bin/bash
# 在Kibana容器使用宿主机的IP地址来访问ES服务(我这里本机的IP地址是10.10.1.129)
$ curl -XGET 'http://10.10.1.129:9200/_cat/health?pretty'
1493707223 06:40:23 ben-es yellow 1 1 11 11 0 0 11 0 - 50.0%
方式三:使用 docker 的 link 机制通信
# 先启动ES容器,并且使用--name指定容器名称为:elasticsearch_2.x_yunyu
$ docker run -itd -p 9200:9200 -p 9300:9300 --name elasticsearch_2.x_yunyu birdben/elasticsearch_2.x:v2
# 启动Kibana容器,并且使用--link指定关联的容器名称为ES的容器名称:elasticsearch_2.x_yunyu
$ docker run -itd -p 5601:5601 --link elasticsearch_2.x_yunyu --name kibana_4.x_yunyu birdben/kibana_4.x:v2
# 查看运行的容器
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
4f26e64bfe82 birdben/kibana_4.x:v2 "docker-entrypoint..." 25 hours ago Up 15 minutes 0.0.0.0:5601->5601/tcp kibana_4.x_yunyu
4d5e7a1058de birdben/elasticsearch_2.x:v2 "docker-entrypoint..." 26 hours ago Up 19 hours 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp elasticsearch_2.x_yunyu
# 在Kibana容器使用--link的容器名称来访问ES服务
$ curl -XGET 'http://elasticsearch_2.x_yunyu:9200/_cat/health?pretty'
1493707223 06:40:23 ben-es yellow 1 1 11 11 0 0 11 0 - 50.0%
实际上-link 机制就是在 Docker 容器中的 /etc/hosts 文件中添加了一个 ES 容器的名称解析。有了这个名称解析后就可以不使用 IP 来和目标容器通信了,除此之外当目标容器重启,Docker 会负责更新 /etc/hosts 文件,因此可以不用担心容器重启后 IP 地址发生了改变,解析无法生效的问题。
Kibana 容器的 /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.2 4d5e7a1058de
ES 容器的 /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.2 elasticsearch_2.x_yunyu 4d5e7a1058de
172.17.0.4 4f26e64bfe82
当 docker 引入网络新特性后,link 机制变的有些多余,但是为了兼容早期版本,-link 机制在默认网络上的功能依旧没有发生变化,docker 引入网络新特性后,内置了一个 DNS Server,但是只有用户创建了自定义网络后,这个 DNS Server 才会起作用。
(待续)
(待续)
Dockerfile是 用来构建Docker镜像的构建文件 ,是由一系列命令和参数构成的脚本。
构建三步骤
以容器centos为例 Docker Official Images
基本规则:
Docker执行Dockerfile的大致流程
docker commit
的操作提交一个新的镜像层从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段:
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
ADD
:将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
CMD
:指定一个容器启动时要运行的命令,Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
COPY
:类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
DockerFile体系结构(保留字指令)
ENTRYPOINT
:指定一个容器启动时要运行的命令,ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数
ENV
:用来在构建镜像过程中设置环境变量
EXPOSE
:当前容器对外暴露出的端口
FROM
:基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER
:镜像维护者的姓名和邮箱地址
ONBUILD
:当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
RUN
:容器构建时需要运行的命令
VOLUME
:容器数据卷,用于数据保存和持久化工作
WORKDIR
:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
部分示例:
ENV MY_PATH /usr/mytest
:这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量,比如:WORKDIR $MY_PATH
COPY src dest
| COPY ["src","dext"]
从构建上下文目录src复制到新的一层镜像内位置dest
CMD 启动命令:
CMD 指定的格式和 RUN 相似,也是两个格式:
CMD <命令>
CMD ["可执行文件","参数1","参数2"...]
CMD ["参数1","参数2"...]
。在指定了 ENTERYPOINT 指令后,用 CMD 指定具体的参数Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的
所以通过自定义mycentos镜像,使其具备:登录后的默认路径、vim编辑器、查看网络配置ifconfig支持
FROM centos # 基于CentOS镜像
MAINTAINER zzyy # 镜像维护者姓名和邮箱
ENV MYPATH /usr/local # 设置环境变量
WORKDIR $MYPATH # 引用环境变量为默认工作目录
RUN yum -y install vim # 构建时运行的命令:安装 vim
RUN yum -y install net-tools # 构建时运行的命令:安装 net-tools,使之支持ifconfig
EXPOSE 80 # 对外暴露的端口
CMD echo $MYPATH # 输出环境变量
CMD echo "success----------------OK" # 输出提示信息
CMD /bin/bash # 执行 /bin/bash
docker build -f /mydocker/Dockerfile -t 新镜像名字:TAG .
。注意:命令最后有一个点,表示当前路径。如果当前路径下有名为Dockerfile的文件,可以省略 -f
及它的参数docker run -it 新镜像名字:TAG
docker history 镜像名
都是指定一个容器启动时要运行的命令
CMD:Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换。比如 tomcat 默认运行指令是:CMD ["catalina.sh", "run"]
,如果运行时附加命令:docker run -it -p 8888:8080 tomcat ls -l
,就会使原来的指令失效导致没有启动。
ENTRYPOINT :docker run
之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合
示例:制作CMD版可以查询IP信息的容器
FROM centos
RUN yum install -y curl
CMD [ "curl", "-s", "https://www.ip.cn" ]
构建三步骤上面的示例已经有了,这里不做赘述
crul命令解释:
yum install curl
安装。curl http://www.baidu.com
这是最简单的使用方法。用这个命令获得了 http://curl.haxx.se 指向的页面,同样,如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地。如果下载的是HTML文档,那么缺省的将只显示文件头部,即HTML文档的header。要全部显示,请加参数 -i
那么问题来了,如果我们希望显示 HTTP 头信息,就需要加上 -i
参数,我们可以看到可执行文件找不到的报错,executable file not found。之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的 -i
替换了原来的 CMD,而不是添加在原来的 curl -s https://www.ip.cn
后面。而 -i
根本不是命令,所以自然找不到。
如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:
docker run myip curl -s https://www.ip.cn -i
但是我们也可以使用 ENTROYPOINT 制作查询IP信息的容器
FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "https://www.ip.cn" ]
此时就可以直接在 docker run 附加参数了
当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "https://www.ip.cn" ]
ONBUILD RUN echo "now,build action is ok========="
构建一个镜像myip :
构建一个子容器,继承于myip容器
FROM myip
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "https://www.ip.cn" ]
mkdir -p /zzyyuse/mydockerfile/tomcat9
FROM centos
MAINTAINER zzyy
# 把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
# 把java与tomcat添加到容器中
ADD jdk-8u171-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.8.tar.gz /usr/local/
# 安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_171
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.8
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.8
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 容器运行时监听的端口
EXPOSE 8080
# 启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.8/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.8/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.8/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.8/bin/logs/catalina.out
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>testdisplay-name>
web-app>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
Insert title here
-----------welcome------------
<%="i am in docker tomcat self "%>
<% System.out.println("=============docker tomcat self");%>
docker search NAME
docker pull IMAGES
docker images
docker run -d IMAGES
docker stop CONTAINER_ID
docker rm CONTAINER_ID
docker pull centos
docker run -itd --name CENTOS_NAME centos /bin/bash
docker exec CENTOS_NAME /bin/bash
ctrl + p + q
docker pull tomcat:7
docker run -d -p 8080:8080 tomcat:7
docker pull mysql:5.6
docker run -d -p 3306:3306 mysql:5.6
使用数据卷方式启动:
docker run -d -p 3306:3306 --name mysql
-v /root/mysql/conf:/etc/mysql/conf.d
-v /root/mysql/logs:/logs
-v /root/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456
mysql:5.6
数据备份:
docker exec myql服务容器ID
sh -c ' exec mysqldump --all-databases -uroot -p"root" '
> /root/all-databases.sql
拉取镜像:docker pull redis
启动容器:docker run -d -p 6379:6379 redis redis-server --appendonly yes
运行redis客户端:docker exec -it [运行着Rediis服务的容器ID] redis-cli
使用数据卷方式启动:
docker run -d -p 6379:6379
-v /root/myredis/data:/data
-v /root/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf
redis redis-name /usr/local/etc/redis/redis.conf
--appendonly yes
在主机 /root/myredis/conf/redis.conf
目录下新建 redis.conf 文件
vim /root/myredis/conf/redis.conf/redis.conf
将redis.conf配置文件写入,这里就不提供配置了,启动后就完成了
Zookeeper 是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用。
所以这里要求安装 zookeeper 及 dubbo-admin 镜像,同时要这两个容器之间建立联系。
docker pull zookeeper
docker run -d
--name zookeeper_name
--restart always
-p 2181:2181
-p 2888:2888
-p 3888:3888
zookeeper
--restart always
:由于 zookeeper“fails fast”,最好始终重启它。EXPOSE 2181 2888 3888
(zookeeper客户端端口,跟随端口,选择端口),因此标准容器链接将使其自动可用于链接的容器。为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序 dubbo-admin ,不过这个监控即使不装也不影响使用。
docker pull chenchuxin/dubbo-admin
docker run -d
-p 8080:8080
-e admin.registry.address=zookeeper://192.168.222.130:2181
-e dubbo.admin.root.password=root
-e dubbo.admin.guest.password=guest
--link [name:alias]
chenchuxin/dubbo-admin
--link list
:当使用–link方式时,作为客户端的container可以通过私有网络形式访问到这个container。同时Docker会在客户端的container中设定一些环境变量来记录绑定的IP和PORT。也就是说相当于使两个容器处于同一网络。
docker pull rabbitmq:3-management
docker run -d
-p 5672:5672
-p 15672:15672
--name myrabbitmq
rabbitmq:3-management
-management
的TAG有web界面通过访问 :http://IP:15672 即可,用户名及密码为 guest
docker pull elasticsearch
docker run -d
-e ES_JAVA_OPTS="-Xms256m -Xmx256m"
-p 9200:9200
-p 9300:9300
--name ES_name
elasticsearch
-e ES_JAVA_OPTS
:表示修改JVM虚拟机的内存,防止内存溢出6.0以上版本默认需要2G大小的内存空间,如果系统没有2G内存运行的时候就会报错:
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
elasticsearch用户拥有的内存权限太小,至少需要262144;
解决方式:
sysctl -w vm.max_map_count=262144
sysctl -a|grep vm.max_map_count
,会显示 vm.max_map_count = 262144
/etc/sysctl.conf
文件最后添加一行 vm.max_map_count=262144
即可永久修改docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]]
docker commit -a theliang -m "new mycentos 1.4 from 1.3 " 45e4aa594e06 mycentos:1.4
docker pull
命令来拉取镜像