Docker是PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并听从Apache2.0协议开源。Docker是经过内核虚拟化技术(namespace以及cgroups等)来提供容器的资源隔离与安全保障。因为Docker经过操做系统层的虚拟化实现隔离,因此Docker容器在运行时,不须要相似虚拟机( VM)额外的操做系统开销,提升资源利用率。html
Docker是使用Go语言编写的一个程序运行、测试、交付的开放平台,Docker被设计为可以使你快速地交付应用。在Docker中,你能够将你的程序分为不一样的基础部分,对于每个基础部分均可以当作一个应用程序来管理。Docker可以帮助你快速地测试、快速地编码、快速地交付,而且缩短你从编码到运行应用的周期。Docker使用轻量级的容器虚拟化平台,而且结合工做流和工具,来帮助你管理、部署你的应用程序。Docker在其核心,Docker实现了让几乎任何程序均可以在一个安全、隔离的容器中运行。安全和隔离可使你能够同时在机器上运行多个容器。Docker容器轻量级的特性,意味着能够获得更多的硬件性能。node
Docker原理:创建-->传送-->运行linux
经过Docker Hub或者本身的Docker仓库分享Docker镜像, 从Docker镜像建立Docker容器, 在容器里运行应用程序。nginx
Docker镜像是如何工做的?
Docker镜像是Docker容器运行时的只读模板,每个镜像由一系列的层(layers)组成;Docker使用UnionFS(联合文件系统)来将这些层联合到一二镜像中,UnionFS文件系统容许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,造成一个单独连贯的文件系统。git
正由于有了这些层(layers)的存在,Docker才会如此的轻量。当你改变了一个Docker镜像,好比升级到某个程序到新的版本,一个新的层会被建立。所以,不用替换整个原先的镜像或者从新创建(在使用虚拟机的时候你可能会这么作),只是一个新的层被添加或升级了。因此你不用从新发布整个镜像,只须要升级。层使得分发Docker镜像变得简单和快速。github
每一个镜像都是从一个基础的镜像开始的,好比ubuntu,一个基础的Ubuntu镜像,或者是Centos,一个基础的Centos镜像。你可使用你本身的镜像做为新镜像的基础,例如你有一个基础的安装了Nginx的镜像,你可使用该镜像来创建你的Web应用程序镜像。(Docker一般从Docker Hub获取基础镜像)docker
Docker镜像从这些基础的镜像建立,经过一种简单、具备描述性的步骤,咱们称之为 指令(instructions)。每个指令会在镜像中建立一个新的层,指令能够包含这些动做:
-> 运行一个命令。
-> 增长文件或者文件夹。
-> 建立一个环境变量。
-> 当运行容器的时候哪些程序会运行。
这些指令存储在Dockerfile文件中。当你须要创建镜像的时候,Docker能够从Dockerfile中读取这些指令而且运行,而后返回一个最终的镜像。shell
Docker仓库的用处?
Docker仓库是Docker镜像的存储仓库。能够推送镜像到Docker仓库中,而后在Docker客户端,能够从Docker仓库中搜索和拉取镜像。数据库
Docker容器是如何工做的?
一个Docker容器包含了一个操做系统、用户添加的文件和元数据(meta-data)。每一个容器都是从镜像创建的,镜像告诉Docker容器内包含了什么,当容器启动时运行什么程序,还有许多配置数据。Docker镜像是只读的,当Docker运行一个从镜像创建的容器,它会在镜像顶部添加一个可读写的层,应用程序能够在这里运行。ubuntu
Docker容器运行时会作哪些事情?
使用docker命令时,Docker客户端都告诉Docker守护进程运行一个容器。
# docker run -i -t ubuntu /bin/bash
能够来分析这个命令,Docker客户端使用docker命令来运行,run参数代表客户端要运行一个新的容器。
Docker客户端要运行一个容器须要告诉Docker守护进程的最小参数信息是:
-> 这个容器从哪一个镜像建立,这里是ubuntu,基础的Ubuntu镜像。
-> 在容器中要运行的命令,这里是/bin/bash,在容器中运行Bash shell。
那么运行这个命令以后在底层发生了什么呢?按照顺序,Docker作了这些事情:
-> 拉取ubuntu镜像:Docker检查ubuntu镜像是否存在,若是在本地没有该镜像,Docker会从Docker Hub下载。若是镜像已经存在,Docker会使用它来建立新的容器。
-> 建立新的容器:当Docker有了这个镜像以后,Docker会用它来建立一个新的容器。
-> 分配文件系统而且挂载一个可读写的层:容器会在这个文件系统中建立,而且一个可读写的层被添加到镜像中。
-> 分配网络/桥接接口:建立一个容许容器与本地主机通讯的网络接口。
-> 设置一个IP地址:从池中寻找一个可用的IP地址而且服加到容器上。
-> 运行你指定的程序:运行指定的程序。
-> 捕获而且提供应用输出:链接而且记录标准输出、输入和错误让你能够看到你的程序是如何运行的。
由此就能够拥有一个运行着的Docker容器了!从这里开始你能够管理你的容器,与应用交互,应用完成以后,能够中止或者删除你的容器。
Docker与VM的区别:
docker与Openstack的对比
Docker用途:简单配置、代码流水线管理、开发效率、应用隔离、服务器整合、调试能力、多租户、快速部署
Docker能够快速交付应用程序
Docker能够为你的开发过程提供完美的帮助。Docker容许开发者在本地包含了应用程序和服务的容器进行开发,以后能够集成到连续的一体化和部署工做流中。举个例子,开发者们在本地编写代码而且使用Docker和同事分享其开发栈。当开发者们准备好了以后,他们能够将代码和开发栈推送到测试环境中,在该环境进行一切所须要的测试。从测试环境中,你能够将Docker镜像推送到服务器上进行部署。
Docker可让开发和拓展更加简单
Docker的以容器为基础的平台容许高度可移植的工做。Docker容器能够在开发者机器上运行,也能够在实体或者虚拟机上运行,也能够在云平台上运行。Docker的可移植、轻量特性一样让动态地管理负载更加简单。你能够用Docker快速地增长应用规模或者关闭应用程序和服务。Docker的快速意味着变更几乎是实时的。
Docker能够达到高密度和更多负载
Docker轻巧快速,它提供了一个可行的、符合成本效益的替代基于虚拟机管理程序的虚拟机。这在高密度的环境下尤为有用。例如,构建你本身的云平台或者PaaS,在中小的部署环境下一样能够获取到更多的资源性能。
Docker改变了什么?
-> 面向产品:产品交付
-> 面向开发:简化环境配置
-> 面向测试:多版本测试
-> 面向运维:环境一致性
-> 面向架构:自动化扩容
Docker组件:镜像(Image)、容器(Container)、仓库(Repository)
Docker 架构:C/S架构
-> Docker使用客户端-服务器(client-server)架构模式。
-> Docker 客户端会与Docker守护进程进行通讯。Docker 守护进程会处理复杂繁重的任务,例如创建、运行、发布你的 Docker 容器。
-> Docker 客户端和守护进程能够运行在同一个系统上,固然也可使用Docker客户端去链接一个远程的 Docker 守护进程。
-> Docker 客户端和守护进程之间经过socket或者RESTful API进行通讯。
Docker守护进程
如上图所示,Docker守护进程运行在一台主机上。用户并不直接和守护进程进行交互,而是经过 Docker 客户端间接和其通讯。
Docker 客户端
Docker 客户端,其实是 docker 的二进制程序,是主要的用户与 Docker 交互方式。它接收用户指令而且与背后的 Docker 守护进程通讯,如此来回往复。
Docker 内部
要理解Docker内部构建,须要理解如下三种部件:
Docker 镜像 - Docker Images
Docker 仓库 - Docker Registry
Docker 容器 - Docker Containers
Docker镜像是Docker容器运行时的只读模板,每个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 容许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,造成一个单独连贯的文件系统。正由于有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,好比升级到某个程序到新的版本,一个新的层会被建立。所以,不用替换整个原先的镜像或者从新创建(在使用虚拟机的时候你可能会这么作),只是一个新 的层被添加或升级了。如今你不用从新发布整个镜像,只须要升级,层使得分发 Docker 镜像变得简单和快速。
Docker仓库用来保存镜像,能够理解为代码控制中的代码仓库。一样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像能够是本身建立,或者在别人的镜像基础上建立。Docker 仓库是 Docker 的分发部分。
Docker容器和文件夹很相似,一个Docker容器包含了全部的某个应用运行所须要的环境。每个 Docker 容器都是从 Docker 镜像建立的。Docker 容器能够运行、开始、中止、移动和删除。每个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。
libcontainer
Docker 从 0.9 版本开始使用 libcontainer 替代 lxc,libcontainer 和 Linux 系统的交互图以下:
下面说下Docker容器的底层技术:Namesapce(资源隔离)和 Cgroup(资源限制)
命名空间 [Namespaces]
=> pid namespace:使用在进程隔离(Process ID)
不一样用户的进程就是经过pid namespace隔离开的,且不一样 namespace 中能够有相同 PID。
具备如下特征:
-> 每一个namespace中的pid是有本身的pid=1的进程(相似 /sbin/init 进程)
-> 每一个 namespace 中的进程只能影响本身的同一个 namespace 或子 namespace 中的进程
-> 由于 /proc 包含正在运行的进程,所以在 container 中的 pseudo-filesystem 的 /proc 目录只能看到本身namespace 中的进程
-> 由于 namespace 容许嵌套,父 namespace 能够影响子 namespace 的进程,因此子 namespace 的进程能够在父namespace中看到,可是具备不一样的 pid
=> mnt namespace:使用在管理挂载点(Mount)
相似 chroot,将一个进程放到一个特定的目录执行。mnt namespace 容许不一样namespace的进程看到的文件结构不一样,这样每一个namespace 中的进程所看到的文件目录就被隔离开了。同 chroot 不一样,每一个 namespace 中的 container 在 /proc/mounts 的信息只包含所在namespace的mount point。
=> net namespace:使用在进程网络接口(Networking)
网络隔离是经过 net namespace 实现的, 每一个 net namespace 有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每一个 container 的网络就能隔离开来。 docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge 链接在一块儿。
=> uts namespace:使用在隔离内核和版本标识 (Unix Timesharing System)
UTS ("UNIX Time-sharing System") namespace 容许每一个 container 拥有独立的 hostname 和 domain name, 使其在网络上能够被视做一个独立的节点而非 Host 上的一个进程。
=> ipc namespace:使用在管理进程间通讯资源 (InterProcess Communication)
container 中进程交互仍是采用 Linux 常见的进程间交互方法 (interprocess communication - IPC), 包括常见的信号量、消息队列和共享内存。然而同 VM 不一样,container 的进程间交互实际上仍是 host 上具备相同 pid namespace 中的进程间交互,所以须要在IPC资源申请时加入 namespace 信息 - 每一个 IPC 资源有一个惟一的 32bit ID。
=> user namespace:使用在管理空户空间
每一个 container 能够有不一样的 user 和 group id, 也就是说能够以 container 内部的用户在 container 内部执行程序而非 Host 上的用户。
有了以上6种namespace从进程、网络、IPC、文件系统、UTS 和用户角度的隔离,一个 container 就能够对外展示出一个独立计算机的能力,而且不一样container从OS层面实现了隔离。然而不一样 namespace 之间资源仍是相互竞争的,仍然须要相似ulimit 来管理每一个container所能使用的资源。
资源配额 [cgroups]
Docker还使用到了cgroups技术来管理群组。使应用隔离运行的关键是让它们只使用你想要的资源。这样能够确保在机器上运行的容器都是良民(good multi-tenant citizens)。群组控制容许Docker分享或者限制容器使用硬件资源。例如,限制指定的容器的内容使用。
cgroups实现了对资源的配额和度量。 cgroups 的使用很是简单,提供相似文件的接口,在 /cgroup 目录下新建一个文件夹便可新建一个 group,在此文件夹中新建 task 文件,并将 pid 写入该文件,便可实现对该进程的资源控制。具体的资源配置选项能够在该文件夹中新建子 subsystem ,{子系统前缀}.{资源项} 是典型的配置方法, 如 memory.usageinbytes 就定义了该 group 在 subsystem memory 中的一个内存限制选项。另外,cgroups 中的 subsystem 能够随意组合,一个 subsystem 能够在不一样的 group 中,也能够一个 group 包含多个 subsystem - 也就是说一个 subsystem。
=> memory
内存相关的限制
=> cpu
在 cgroup 中,并不能像硬件虚拟化方案同样可以定义 CPU 能力,可是可以定义 CPU 轮转的优先级,所以具备较高 CPU 优先级的进程会更可能获得 CPU 运算。 经过将参数写入 cpu.shares ,便可定义改 cgroup 的 CPU 优先级 - 这里是一个相对权重,而非绝对值
=> blkio
block IO 相关的统计和限制,byte/operation 统计和限制 (IOPS 等),读写速度限制等,可是这里主要统计的都是同步 IO
=> devices
设备权限限制
Docker 联合文件系统
联合文件系统(UnionFS)是用来操做建立层的,使它们轻巧快速。Docker使用UnionFS提供容器的构造块。Docker可使用不少种类的UnionFS包括AUFS, btrfs, vfs, and DeviceMapper。
Docker 容器格式
Docker链接这些组建到一个包装中,称为一个 container format(容器格式)。默认的容器格式是libcontainer。Docker一样支持传统的Linux容器使用LXC。在将来,Docker也许会支持其它的容器格式,例如与BSD Jails 或 Solaris Zone集成。
======================== Docker环境的安装部署 ==========================
环境准备(centos7)
# yum install -y docker # systemctl start docker # systemctl enable docker
镜像的查看(docker images信息结果包括:镜像仓库、标签、镜像ID、建立时间、镜像大小 )
[root@linux-node2 ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE docker.io/centos latest 60e65a8e4030 36 hours ago 196.6 MB docker.io/nginx latest 813e3731b203 9 days ago 133.8 MB docker.io/registry latest a8706c2bfd21 2 weeks ago 422.8 MB
镜像的导出、导入和下载(能够将本机下载的镜像导出,而后将导出文件上传到别的机器上,在别的机器上进行镜像导入)
[root@linux-node2 ~]# docker pull centos [root@linux-node2 ~]# docker save centos > /opt/centos.tar.gz 将linux-node2的镜像导出文件上传到linux-node1机器上,而后在linux-node1机器上导入 [root@linux-node1 ~]# docker load < /opt/centos.tar.gz
镜像的删除(rmi后面能够跟多个id,用空格隔开)
docker rmi container_id
[root@linux-node2 ~]# docker rmi 813e3731b203
Docker重命名镜像名称和TAG
# docker tag IMAGEID(镜像id) REPOSITORY:TAG(仓库:标签)
[root@docker-test2 ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE <none> <none> 93ec41b5ed04 About an hour ago 435.9 MB [root@docker-test2 ~]# docker tag 93ec41b5ed04 kevin/nginx:v1 [root@docker-test2 ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE kevin/nginx v1 93ec41b5ed04 About an hour ago 435.9 MB
首次建立一个简单的容器
[root@linux-node2 ~]# docker run centos /bin/echo "hehe" hehe
查看容器状态
可使用docker ps只能看见存活的容器,docker ps -a 查看所有的容器,结果信息表示:
容器ID、使用的镜像、执行的命令、建立的时间、状态、端口、名称(若是不指定,自动生成)
[root@linux-node2 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES daeb4d7f7aab centos "/bin/echo hehe" About a minute ago Exited (0) About a minute ago insane_einstein
建立容器
--name:指定容器名称
-t :分配一个tty终端
-i :容器的标准输保持打开的状态
[root@linux-node2 ~]# docker run --name mydocker -t -i centos /bin/bash [root@94ab7a046f7c /]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 11772 1872 ? Ss 03:42 0:00 /bin/bash root 14 0.0 0.0 35888 1472 ? R+ 03:43 0:00 ps aux
这种方式建立自动进入容器,开启的容器只执行/bin/bash;
在容器中查看主机名
[root@94ab7a046f7c /]# hostname 94ab7a046f7c [root@94ab7a046f7c /]# exit
启动、中止容器
# docker stop ID # docker start ID
进入容器
[root@linux-node2 ~]# docker attach 94ab7a046f7c [root@94ab7a046f7c /]#
删除容器
[root@linux-node2 ~]# docker rm ID/名称 加-f 强制删除,包括正在运行中的容器
映射
随机映射 (端口的映射是系统自动分配的)
[root@linux-node2 ~]# docker run -d -P nginx 90316d97ee975b4e62e1927a9fb31f20703556b1a3ea07880d0c68dcb5bbd3bb [root@linux-node2 ~]# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 90316d97ee97 nginx "nginx -g 'daemon off" 25 seconds ago Up 23 seconds 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp ecstatic_almeida
指定映射 (以下,指定容器的80端口映射到主机的81端口上)
[root@linux-node2 ~]# docker run -d -p 81:80 nginx 0294a8f5b4fc81ba31383a8eb98ec62b136826eba92360c84afd87bf1bf819fc [root@linux-node2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0294a8f5b4fc nginx "nginx -g 'daemon off" 11 seconds ago Up 10 seconds 443/tcp, 0.0.0.0:81->80/tcp admiring_ramanujan
查看日志
命令为"docker logs +ID"
数据管理
数据卷
默认挂载目录
建立一个数据卷,名称是volume-test1,挂载到data下默认挂载目录
[root@linux-node2 ~]# docker run -it --name volume-test1 -v /data centos [root@1768d6414cfc /]# ls -l /data/ total 0
列出容器的全部信息,查看mounts模块
[root@linux-node2 ~]# docker inspect 1768d6414cfc "Mounts": [ { "Name": "55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167", "Source": "/var/lib/docker/volumes/55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167/_data", "Destination": "/data", "Driver": "local", "Mode": "", "RW": true } ],
查找挂载点并进入
[root@linux-node2 ~]# ll /var/lib/docker/volumes/55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167/_data 总用量 0 [root@linux-node2 ~]# cd /var/lib/docker/volumes/55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167/_data
建立一个cgt测试,并从新回到容器中查看
[root@linux-node2 _data]# mkdir cgt 去容器中查看 [root@1768d6414cfc /]# ls -l /data/ total 4 drwxr-xr-x 2 root root 4096 Jan 4 14:04 cgt
指定挂载目录。 将容器的/opt映射到主机的/opt目录下(下面命令中前一个是主机路径,后一个是容器路径)
[root@linux-node2 ~]# docker run -it --name volume-test1 -v /opt:/opt centos
指定权限
只须要在挂载后面加上权限便可。rw为读写,ro为只读
[root@linux-node2 ~]# docker run -it --name volume-test1 -v /opt:/opt:rw centos
挂载单个文件
记录历史记录
[root@linux-node2 ~]# docker run -it -v ~/.bash_history:/.bash_history centos
数据卷容器
让一个容器能够访问另外一个容器的数据卷。启动两个容器
启动nfs容器,挂在一个卷,使用-d直接在后台执行 [root@linux-node2 ~]# docker run -d --name nfs -v /data centos 209bc89b365ad6bc1eeae693ada01c04c2d08e9ee2b8816e624882944c116126 启动test1容器,挂载到nfs的数据卷容器上, [root@linux-node2 ~]# docker run -it --name test1 --volumes-from nfs centos [root@5e399198d6a8 /]# ls /data/ 查看没内容
找到nfs容器的挂载点(可使用名称,不只仅是ID)
找到nfs容器的ID [root@linux-node2 opt]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 209bc89b365a centos "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago nfs 找到nfs容器的挂载点 [root@linux-node2 _data]# docker inspect nfs [root@linux-node2 opt]# cd /var/lib/docker/volumes/3938c9b1143d41340e148a4c7bc12d13b53966b15380c5b958a9e035897450d5/_data [root@linux-node2 _data]# touch cgt
在test1上查看
[root@5e399198d6a8 /]# ls /data/ cgt
注意:数据卷容器不论中止仍是开启,不影响其余容器挂载使用
如何制做镜像
方式一:手动构建容器
1)建立一个容器mynginx,使用centos镜像
[root@linux-node2 ~]# docker run --name mynginx -it centos [root@f9c7dfb6f552 /]# rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm [root@f9c7dfb6f552 /]# yum -y install nginx [root@f9c7dfb6f552 /]# exit exit
2)基于mynginx容器作一个镜像mynginx:v1
[root@linux-node2 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f9c7dfb6f552 centos "/bin/bash" 3 minutes ago Exited (0) 15 seconds ago mynginx 基于mynginx这个容器作一个镜像 [root@linux-node2 ~]# docker commit -m "my nginx" f9c7dfb6f552 cgt/mynginx:v1 3f3adc859b77b2b47c3631229761bee6c7066f1c708bc01c5173c2ef5c0adce8 提交镜像,同时打一个标签叫mynginx:v1,cgt至关于你向github上提交的用户名 查看镜像 [root@linux-node2 ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE cgt/mynginx v1 3f3adc859b77 About a minute ago 326.4 MB
3)基于mynginx:v1建立一个容器mynginxv1,目的是修改nginx不让其在后台运行
[root@linux-node2 ~]# docker run -it --name nginxv1 cgt/mynginx:v1 [root@ea64c5855006 /]# vi /etc/nginx/nginx.conf daemon off; # 再也不后台运行 [root@ea64c5855006 /]# exit exit [root@linux-node2 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ea64c5855006 cgt/mynginx:v1 "/bin/bash" 2 minutes ago Exited (0) 42 seconds ago nginxv1
4)基于mynginxv1提交mynginxv2版本
从新提交V2版本 [root@linux-node2 ~]# docker commit -m "my nginx" ea64c5855006 cgt/mynginx:v2 a480cdf9055ec4e640c65df6404c6ba42903ea77198a26cec75eef0e4965fe67 查看V2镜像 [root@linux-node2 ~]# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE cgt/mynginx v2 a480cdf9055e 25 seconds ago
5)基于mynginxv2镜像,建立mynginxv2容器
启动容器,-d后台运行,-p指定端口 在后面是镜像,最后是命令(由于是yum安装的,能够直接写nginx,若是不是yum,那要写绝对路径) [root@linux-node2 ~]# docker run -d -p 82:80 cgt/mynginx:v2 nginx 4eaf8a19034a673100f9355504628fad45e6ecbab91615afd6cb4e7a18b82171 [root@linux-node2 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4eaf8a19034a cgt/mynginx:v2 "nginx" 15 seconds ago Up 14 seconds 0.0.0.0:82->80/tcp elegant_leakey 能够在浏览器访问82端口
方式二:Dockerfile
1)Dockerfile包含的信息
- 基础镜像信息
- 维护者信息
- 镜像操做指令
- 容器启动时执行指令
2)文件的编写
[root@linux-node2 ~]# mkdir /opt/dockerfile/nginx/ -p [root@linux-node2 ~]# cd /opt/dockerfile/nginx/ 将index.html上传到此处 [root@linux-node2 nginx]# vim Dockerfile # This is docker file # version v1 # Author wangshibo # Base image(基础镜像) FROM centos # Maintainer(维护者信息) MAINTAINER wangshibo 2134728394@qq.com # Commands(执行命令) RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm RUN yum -y install nginx # Add(添加文件) ADD index.html /usr/share/nginx/html/index.html # index.html是本身编写的文件,放在后面的目录中,由于yum安装后Documentroot是在这里 RUN echo "daemon off;" >>/etc/nginx/nginx.conf EXPOSE 80 # 对外的端口 CMD ['nginx'] # 执行的命令
3)构建容器,并运行。 创建newnginx容器,-t:标签,执行/opt/dockerfile/nginx/下面的默认的Dockerfile文件
[root@linux-node2 nginx]# docker build -t cgt/mynginx:v3 /opt/dockerfile/nginx/ [root@linux-node2 nginx]# docker run -d -p 83:80 cgt/mynginx:v3
Docker是一个开源的应用容器引擎,让开发者能够打包他们的应用以及依赖包到一个可移植的容器中,而后发布到任何流行的Linux机器上,也能够实现虚拟化。当你真正投入容器Docker的怀抱,不但能够发现它能解决不少问题,并且还具备众多的优势:
-> 它是不可变的-操做系统,库版本,配置,文件夹和应用都是同样的。您可使用经过相同QA测试的镜像,使产品具备相同的表现。
-> 它是轻量级的-容器的内存占用很是小。不须要几百几千MB,它只要对主进程分配内存再加上几十MB。
-> 它很快速-启动一个容器与启动一个单进程同样快。不须要几分钟,您能够在几秒钟内启动一个全新的容器。
许多用户依然像对待典型的虚拟机那样对待容器,彷佛都忘记了除了与虚拟机类似的部分,容器还有一个很大的优势:它是一次性的。这个"特性"自己促使用户改变他们关于使用和管理容器的习惯;下面将会说明下在容器中不该该作这些事,以确保最大地发挥容器的做用。
-> 不要在容器中存储数据 – 容器可能被中止,销毁,或替换。一个运行在容器中的程序版本1.0,应该很容易被1.1的版本替换且不影响或损失数据。有鉴于此,若是你须要存储数据,请存在卷中,而且注意若是两个容器在同一个卷上写数据会致使崩溃。确保你的应用被设计成在共享数据存储上写入。
-> 不要将你的应用发布两份 – 一些人将容器视为虚拟机。他们中的大多数倾向于认为他们应该在现有的运行容器里发布本身的应用。在开发阶段这样是对的,此时你须要不断地部署与调试;但对于质量保证与生产中的一个连续部署的管道,你的应用本该成为镜像的一部分。记住:容器应该保持不变。
-> 不要建立超大镜像 – 一个超大镜像只会难以分发。确保你仅有运行你应用/进程的必需的文件和库。不要安装没必要要的包或在建立中运行更新(yum更新)。
-> 不要使用单层镜像 – 要对分层文件系统有更合理的使用,始终为你的操做系统建立你本身的基础镜像层,另一层为安全和用户定义,一层为库的安装,一层为配置,最后一层为应用。这将易于重建和管理一个镜像,也易于分发。
-> 不要为运行中的容器建立镜像 – 换言之,不要使用"docker commit"命令来建立镜像。这种建立镜像的方法是不可重现的也不能版本化,应该完全避免。始终使用Dockerfile或任何其余的可彻底重现的S2I(源至镜像)方法。
-> 不要只使用"最新"标签 – 最新标签就像Maven用户的"快照"。标签是被鼓励使用的,尤为是当你有一个分层的文件系统。你总不但愿当你2个月以后建立镜像时,惊讶地发现你的应用没法运行,由于最顶的分层被非向后兼容的新版本替换,或者建立缓存中有一个错误的"最新"版本。在生产中部署容器时应避免使用最新。
-> 不要在单一容器中运行超过一个进程-容器能完美地运行单个进程(http守护进程,应用服务器,数据库),但若是运行多个进程,管理、获取日志、独立更新都会遇到麻烦。
-> 不要在镜像中存储凭据。使用环境变量 –不要将镜像中的任何用户名/密码写死。使用环境变量来从容器外部获取此信息。
-> 使用非root用户运行进程 – "docker容器默认以root运行。(…)随着docker的成熟,更多的安全默认选项变得可用。现现在,请求root对于其余人是危险的,可能没法在全部环境中可用。你的镜像应该使用USER指令来指令容器的一个非root用户来运行。"
-> 不要依赖IP地址 – 每一个容器都有本身的内部IP地址,若是你启动并中止它地址可能会变化。若是你的应用或微服务须要与其余容器通信,使用任何命名与(或者)环境变量来从一个容器传递合适信息到另外一个。