Docker之Docker概念,网络,数据卷
1 Docker
1.1 简介
Docker
最初是 dotCloud
公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,于 2013 年 3 月以 Apache 2.0
授权协议开源,主要项目代码在 GitHub
上进行维护。Docker 使用 Google 公司推出的 Go 语言 进行开发实现。docker
是linux容器的一种封装,提供简单易用的容器使用接口。它是最流行的Linux容器
解决方案。
docker
的接口相当简单,用户可以方便的创建、销毁容器。docker
将应用程序与程序的依赖,打包在一个文件里面。运行这个文件就会生成一个虚拟容器。程序运行在虚拟容器里,如同在真实物理机上运行一样,有了docker,就不用担心环境问题了
1.2 Docker架构
Docker
包括三个基本概念:
- 镜像(
Image
):Docker
镜像(Image
),就相当于是一个root
文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。- 通过镜像启动一个容器,一个镜像是一个可执行的包,其中包括运行应用程序所需要的所有内容包含代码,运行时间,库、环境变量、和配置文件。
Docker
镜像也是一个压缩包,只是这个压缩包不只是可执行文件,环境部署脚本,它还包含了完整的操作系统。因为大部分的镜像都是基于某个操作系统来构建,所以很轻松的就可以构建本地和远端一样的环境,这也是Docker
镜像的精髓。
- 容器(
Container
):镜像(Image
)和容器(Container
)的关系,就像是面向对象程序设计中的类
和实例
一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建
、启动
、停止
、删除
、暂停
等。
所创建的每一个容器都是相互隔离
、互不可见
,以保证平台的安全性。可以把容器看做是一个简易版的linux
环境(包括root用户权限、镜像空间、用户空间和网络空间等)和运行在其中的应用程序 - 仓库(
Repository
):仓库可看成一个代码控制中心,用来保存镜像。- 仓库注册服务器上往往存放着多个仓库,每个仓库中包含了多个镜像,每个镜像有不同标签(
tag
) - 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
- 最大的公开仓库是
Docker Hub:https://hub.docker.com
,存放了数量庞大的镜像供用户下载。
国内的公开仓库包括阿里云 、网易云等
- 仓库注册服务器上往往存放着多个仓库,每个仓库中包含了多个镜像,每个镜像有不同标签(
Docker
使用客户端-服务器 (C/S
) 架构模式,使用远程API来管理和创建Docker容器,Docker
容器通过 Docker
镜像来创建
概念 | 说明 |
---|---|
Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 |
Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体 |
Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
Docker Registry | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure |
1.3 Docker与虚拟机的区别
虚拟机通过添加Hypervisor
层(虚拟化中间层),虚拟出网卡、内存、CPU
等虚拟硬件,再在其上建立虚拟机,每个虚拟机都有自己的系统内核。而Docker
容器则是通过隔离(namesapce
)的方式,将文件系统、进程、设备、网络等资源进行隔离,再对权限、CPU
资源等进行控制(cgroup
),最终让容器之间互不影响,容器无法影响宿主机。
与虚拟机相比,容器资源损耗要少。同样的宿主机下,能够建立容器的数量要比虚拟机多
但是,虚拟机的安全性要比容器稍好,而docker
容器与宿主机共享内核、文件系统等资源,更有可能对其他容器、宿主机产生影响
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为MB | 一般为GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般是几十个 |
1.4 Docker 如何工作
Docker
技术使用 Linux
内核和内核功能(例如 Cgroups 和 namespaces)来分隔进程,以便各进程相互独立运行。这种独立性正是采用容器的目的所在;它可以独立运行多种进程、多个应用程序,更加充分地发挥基础设施的作用,同时保持各个独立系统的安全性。
容器工具(包括 Docker)可提供基于镜像的部署模式。这使得它能够轻松跨多种环境,与其依赖程序共享应用或服务组。Docker
还可在这一容器环境中自动部署应用程序(或者合并多种流程,以构建单个应用程序)。
此外,由于这些工具基于 Linux
容器构建,使得 Docker
既易于使用,又别具一格 —— 它可为用户提供前所未有的高度应用程访问权限、快速部署以及版本控制和分发能力。
1.5 Docker技术是否与传统的Linux容器相同
答案:否
Docker
技术最初是基于 LXC
技术构建(大多数人都会将这一技术与传统的 Linux
容器联系在一起),但后来它逐渐摆脱了对这种技术的依赖。
就轻量级虚拟化这一功能来看,LXC
非常有用,但它无法提供出色的开发人员或用户体验。除了运行容器之外,Docker
技术还具备其他多项功能,包括简化用于构建容器、传输镜像以及控制镜像版本的流程。
传统的 Linux
容器使用 init
系统来管理多种进程。这意味着,所有应用程序都作为一个整体运行。与此相反,Docker
技术鼓励应用程序各自独立运行其进程,并提供相应工具以实现这一功能。这种精细化运作模式自有其优势。
1.5.1 什么是 Linux 容器
Linux
容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。
更加详细地来说,假定在开发一个应用。使用的是一台笔记本电脑,而开发环境具有特定的配置。其他开发人员身处的环境配置可能稍有不同。正在开发的应用依赖于当前的配置,还要依赖于某些特定文件。与此同时,企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。你希望尽可能多在本地模拟这些环境,而不产生重新创建服务器环境的开销。
因此,你要如何确保应用能够在这些环境中运行和通过质量检测,并且在部署过程中不出现令人头疼的问题,也无需重新编写代码和进行故障修复?
答案就是使用容器
。
容器
可以确保你的应用拥有必需的配置和文件,使得这些应用能够在从开发到测试、再到生产的整个流程中顺利运行,而不出现任何不良问题。
虽然这只是简化的示例,但在需要很高的可移植性、可配置性和隔离的情况下,我们可以利用 Linux
容器通过很多方式解决难题。无论基础架构是在企业内部还是在云端,或者混合使用两者,容器都能满足你的需求。
1.5.2 容器是虚拟化吗
是,但也不竟然。我们用一种简单方式来思考一下:
虚拟化
使得许多操作系统可同时在单个系统上运行。容器则可共享同一个操作系统内核,将应用进程与系统其他部分隔离开。
这意味着什么?首先,让多个操作系统在单个虚拟机监控程序上运行以实现虚拟化,并不能达成和使用容器同等的轻量级效果。事实上,在仅拥有容量有限的有限资源时,需要能够可以进行密集部署的轻量级应用。Linux
容器可从单个操作系统运行,在所有容器中共享该操作系统,因此应用和服务能够保持轻量级,并行快速运行
1.6 Docker中的镜像分层
参考文档:http://www.maiziedu.com/wiki/cloud/dockerimage
Docker
支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub
中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。
从上图可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
1.6.1 Docker镜像为什么分层
镜像分层最大的一个好处就是共享资源
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是不会被修改的,修改只会被限制在单个容器内。这就是容器 Copy-on-Write
特性。
1.5.2 可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作容器层
,容器层
之下的都叫镜像层
。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
1.6.3 容器层的细节说明
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
文件操作说明
文件操作 | 说明 |
---|---|
添加文件 | 在容器中创建文件时,新文件被添加到容器层 中 |
读取文件 | 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找 此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存 |
修改文件 | 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此 文件。一旦找到,立即将其复制到容器层,然后修改之 |
删除文件 | 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找 此文件。找到后,会在容器层中 记录下此删除操作 。(只是记录删除操作) |
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write
。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
1.7 Docker网络类型
1.7.1 docker的网络类型
类型 | 说明 |
---|---|
None | 不为容器配置任何网络功能,没有网络 --net=none |
Container | 与另一个运行中的容器共享Network Namespace,--net=container:containerID |
Host | 与主机共享Network Namespace,--net=host |
Bridge | Docker设计的NAT网络模型(默认类型) |
Bridge
默认docker
网络隔离基于网络命名空间,在物理机上创建docker
容器时会为每一个docker
容器分配网络命名空间,并且把容器IP
桥接到物理机的虚拟网桥上。
1.7.1.1 host模式
host
模式 :使用 --net=host
指定
相当于VMware
中的桥接模式
,与宿主机在同一个网络中,但是没有独立IP地址
Docker
使用了Linux
的Namespace
技术来进行资源隔离,如PID Namespace
隔离进程,Mount Namespace
隔离文件系统,Network Namespace
隔离网络等。
一个Network Namespace
提供了一份独立的网络环境,包括网卡,路由,iptable
规则等都与其他Network Namespace
隔离。
一个Docker
容器一般会分配一个独立的Network Namespace
但是如果启动容器的时候使用host
模式,那么这个容器将不会获得一个独立的Network Namespace
,而是和宿主机共用一个Network Namespace
。容器将不会虚拟出自己的网卡,配置自己的IP
等,而是使用宿主机的IP
和端口。此时容器不再拥有隔离的、独立的网络栈。不拥有所有端口资源
1.7.1.2 container模式
container
模式:使用--net=container:contatiner:NAME_or_ID
指定
这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace
,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围等。 可以在一定程度上节省网络资源,容器内部依然不会拥有所有端口。
同样,两个容器除了网络方面,其他的如文件系统,进程列表等还是隔离的。
两个容器的进程可以通过lo网卡设备通信
1.7.1.3 none 模式
none
模式:使用 --net=none
指定
使用none
模式,docker
容器有自己的network Namespace
,但是并不为Docker
容器进行任何网络配置。也就是说,这个Docker
容器没有网卡,ip
, 路由等信息。
这种网络模式下,容器只有lo
回环网络,没有其他网卡。
这种类型没有办法联网,但是封闭的网络能很好的保证容器的安全性
该容器将完全独立于网络,用户可以根据需要为容器添加网卡。此模式拥有所有端口。(none
网络模式配置网络)特殊情况下才会用到,一般不用
1.7.1.4 bridge模式
相当于Vmware
中的 nat
模式,容器使用独立network Namespace
,并连接到docker0
虚拟网卡。通过docker0
网桥以及iptables nat
表配置与宿主机通信,此模式会为每一个容器分配Network Namespace
、设置IP
等,并将一个主机上的 Docker
容器连接到一个虚拟网桥上。
当Docker
进程启动时,会在主机上创建一个名为docker0
的虚拟网桥,此主机上启动的Docker
容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0
子网中分配一个IP
给容器使用,并设置docker0
的IP
地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair
设备。veth
设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth
设备常用来连接两个网络设备。
Docker
将veth pair
设备的一端放在新创建的容器中,并命名为eth0
(容器的网卡),另一端放在主机中, 以veth*
这样类似的名字命名,并将这个网络设备加入到docker0
网桥中。可以通过 brctl show
命令查看。
容器之间通过veth pair
进行访问
使用docker run -p
时,docker
实际是在iptables
做了DNAT
规则,实现端口转发功能。
可以使用iptables -t nat -vnL
查看
转载于:https://mp.weixin.qq.com/s/VkRQyvXfo-dLem5Bv0094w
1.7.2 不为容器配置网络功能
此模式下创建容器是不会为容器配置任何网络参数的,如:容器网卡、IP、通信路由等,全部需要自己去配置。
[root@docker01 ~]# docker run -it --network none busybox:latest /bin/sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
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
1.7.3 与其他容器共享网络配置(Container)
此模式和host模式很类似,只是此模式创建容器共享的是其他容器的IP和端口而不是物理机,此模式容器自身是不会配置网络和端口,创建此模式容器进去后,你会发现里边的IP是你所指定的那个容器IP并且端口也是共享的,而且其它还是互相隔离的,如进程等。
[root@docker01 ~]# docker run -it --network container:mywordpress_db_1 busybox:latest /bin/sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue
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
105: eth0@if106: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
1.7.4 使用宿主机网络
此模式创建的容器没有自己独立的网络命名空间,是和物理机共享一个Network Namespace,并且共享物理机的所有端口与IP,并且这个模式认为是不安全的。
[root@docker01 ~]# docker run -it --network host busybox:latest /bin/sh
1.7.5 查看网络列表
[root@docker01 ~]# docker network list
NETWORK ID NAME DRIVER SCOPE
b15e8a720d3b bridge bridge local
345d65b4c2a0 host host local
bc5e2a32bb55 mywordpress_default bridge local
ebf76eea91bb none null local
1.7.6 用PIPEWORK为docker容器配置独立IP
参考文档:http://blog.csdn.net/design321/article/details/48264825
官方网站:https://github.com/jpetazzo/pipework
宿主环境:centos7.2
1、安装pipework
wget https://github.com/jpetazzo/pipework/archive/master.zip
unzip master.zip
cp pipework-master/pipework /usr/local/bin/
chmod +x /usr/local/bin/pipework
2、配置桥接网卡
安装桥接工具
yum install bridge-utils.x86\_64 -y
修改网卡配置,实现桥接
# 修改eth0配置,让br0实现桥接
[root@docker01 ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE=Ethernet
BOOTPROTO=static
NAME=eth0
DEVICE=eth0
ONBOOT=yes
BRIDGE=br0
[root@docker01 ~]# cat /etc/sysconfig/network-scripts/ifcfg-br0
TYPE=Bridge
BOOTPROTO=static
NAME=br0
DEVICE=br0
ONBOOT=yes
IPADDR=10.0.0.100
NETMASK=255.255.255.0
GATEWAY=10.0.0.254
DNS1=223.5.5.5
# 重启网络
[root@docker01 ~]# /etc/init.d/network restart
3、运行一个容器镜像测试:
pipework br0 \$\(docker run -d -it -p 6880:80 --name httpd\_pw httpd\) 10.0.0.220/24\@10.0.0.254
在其他主机上测试端口及连通性
[root@docker01 ~]# curl 10.0.0.220
<html><body><h1>It works!</h1></body></html>
[root@docker01 ~]# ping 10.0.0.220 -c 1
PING 10.0.0.220 (10.0.0.220) 56(84) bytes of data.
64 bytes from 10.0.0.220: icmp_seq=1 ttl=64 time=0.043 ms
4、再运行一个容器,设置网路类型为none:
pipework br0 $(docker run -d -it --net=none --name test httpd:2.4) 10.0.0.221/24@10.0.0.254
进行访问测试
[root@docker01 ~]# curl 10.0.0.221
<html><body><h1>It works!</h1></body></html>
5、重启容器后需要再次指定:
pipework br0 testduliip 172.16.146.113/24\@172.16.146.1 pipework br0 testduliip01 172.16.146.112/24\@172.16.146.1
Docker跨主机通信之overlay可以参考:
http://www.cnblogs.com/CloudMan6/p/7270551.html
1.7.7 Docker跨主机通信之macvlan
创建网络
[root@docker01 ~]# docker network create --driver macvlan --subnet 10.1.0.0/24 --gateway 10.1.0.254 -o parent=eth0 macvlan_1
33a1f41dcc074f91b5bd45e7dfedabfb2b8ec82db16542f05213839a119b62ca
设置网卡为混杂模式
ip link set eth0 promisc on
创建使用macvlan网络容器
[root@docker02 ~]# docker run -it --network macvlan_1 --ip=10.1.0.222 busybox /bin/sh
1.8 Docker 数据卷的管理
1.8.1 定义
数据卷
是一个供容器使用的特殊目录,位于容器中。可将宿主机的目录挂载到数据卷上,对数据卷的修改操作立刻可见,并且更新数据不会影响镜像,从而实现数据在宿主机
与容器
之间的迁移。数据卷的使用类似于Linux
下对目录进行的mount
操作。
如果需要在容器之间共享一些数据,最简单的方法就是使用数据卷容器。数据卷容器是一个普通的容器,专门提供数据卷给其他容器挂载使用。
容器互联是通过容器的名称在容器间建立一条专门的网络通信隧道
。简单点说,就是会在源容器和接收容器之间建立一条隧道,接收容器可以看到源容器指定的信息
1.8.2 挂载时创建卷
挂载卷
[root@docker01 ~]# docker run -d -p 80:80 -v /data:/usr/share/nginx/html nginx:latest
079786c1e297b5c5031e7a841160c74e91d4ad06516505043c60dbb78a259d09
容器内站点目录: /usr/share/nginx/html
在宿主机写入数据,查看
[root@docker01 ~]# echo "http://www.nmtui.com" >/data/index.html
[root@docker01 ~]# curl 10.0.0.100
http://www.nmtui.com
设置共享卷,使用同一个卷启动一个新的容器
[root@docker01 ~]# docker run -d -p 8080:80 -v /data:/usr/share/nginx/html nginx:latest
351f0bd78d273604bd0971b186979aa0f3cbf45247274493d2490527babb4e42
[root@docker01 ~]# curl 10.0.0.100:8080
http://www.nmtui.com
查看卷列表
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
1.8.3 创建卷后挂载
创建一个卷
[root@docker01 ~]# docker volume create
f3b95f7bd17da220e63d4e70850b8d7fb3e20f8ad02043423a39fdd072b83521
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local f3b95f7bd17da220e63d4e70850b8d7fb3e20f8ad02043423a39fdd072b83521
指定卷名
[root@docker01 ~]# docker volume ls
DRIVER VOLUME NAME
local clsn
local f3b95f7bd17da220e63d4e70850b8d7fb3e20f8ad02043423a39fdd072b83521
查看卷路径
[root@docker01 ~]# docker volume inspect clsn
[
{
"CreatedAt": "2018-02-01T00:39:25+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/clsn/_data",
"Name": "clsn",
"Options": {},
"Scope": "local"
}
]
使用卷创建
[root@docker01 ~]# docker run -d -p 9000:80 -v clsn:/usr/share/nginx/html nginx:latest
1434559cff996162da7ce71820ed8f5937fb7c02113bbc84e965845c219d3503
# 宿主机测试
[root@docker01 ~]# echo 'blog.nmtui.com' >/var/lib/docker/volumes/clsn/_data/index.html
[root@docker01 ~]# curl 10.0.0.100:9000
blog.nmtui.com
设置卷
[root@docker01 ~]# docker run -d -P --volumes-from 079786c1e297 nginx:latest
b54b9c9930b417ab3257c6e4a8280b54fae57043c0b76b9dc60b4788e92369fb
1.8.4 手动将容器保存为镜像
本次是基于docker官方centos 6.8 镜像创建
官方镜像列表:https://hub.docker.com/explore/
启动一个centos6.8的镜像
[root@docker01 ~]# docker pull centos:6.8
[root@docker01 ~]# docker run -it -p 1022:22 centos:6.8 /bin/bash
# 在容器种安装sshd服务,并修改系统密码
[root@582051b2b92b ~]# yum install openssh-server -y
[root@582051b2b92b ~]# echo "root:123456" |chpasswd
[root@582051b2b92b ~]# /etc/init.d/sshd start
启动完成后镜像ssh连接测试
将容器提交为镜像
[root@docker01 ~]# docker commit brave_mcclintock centos6-ssh
使用新的镜像启动容器
[root@docker01 ~]# docker run -d -p 1122:22 centos6-ssh:latest /usr/sbin/sshd -D
5b8161fda2a9f2c39c196c67e2eb9274977e7723fe51c4f08a0190217ae93094
在容器安装httpd服务
[root@5b8161fda2a9 /]# yum install httpd -y
编写启动脚本脚本
[root@5b8161fda2a9 /]# cat init.sh
#!/bin/bash
/etc/init.d/httpd start
/usr/sbin/sshd -D
[root@5b8161fda2a9 /]# chmod +x init.sh
# 注意执行权限
注意执行权限
再次提交为新的镜像
[root@docker01 ~]# docker commit 5b8161fda2a9 centos6-httpd
sha256:705d67a786cac040800b8485cf046fd57b1828b805c515377fc3e9cea3a481c1
启动镜像,做好端口映射。并在浏览器中测试访问
[root@docker01 ~]# docker run -d -p 1222:22 -p 80:80 centos6-httpd /init.sh
46fa6a06644e31701dc019fb3a8c3b6ef008d4c2c10d46662a97664f838d8c2c
参考文献:
https://mp.weixin.qq.com/s/8Dt_negpFfecJRsgWwWfsA
https://mp.weixin.qq.com/s/oujJYbWITT_5pqoDDyxKPw