Docker能作些什么?java
1.docker可以解决虚拟机可以解决的问题linux
2.隔离应用依赖web
3.建立应用镜像并复制docker
4.建立容易分发的即启即用的应用shell
5.docker的想法是建立软件程序可移植的轻量容器apache
镜像ubuntu
1.docker的镜像相似虚拟机的快照vim
2.在现有镜像的基础上建立镜像windows
容器浏览器
1.能够从镜像中建立容器
2.容器和虚拟机同样是隔离的,它也拥有一个惟一ID和惟一供读人的名字,docker容许公开容器的公开端口
3.容器是被来设计运行一个应用的 而不是一台机器
4.容器应该是短暂和一次性的
连接:
1.容器启动时将会被分配一个私有IP,其余容器可使用这个IP与其进行通信,所以,容器能够共享一个本地网络
2.docker容许你在建立一个新容器时引用其余现存容器,在你刚建立的容器中被引用的容器会得到一个别名,咱们就能够定义 ,这两个容器连接在了一块儿。
3.好比一个DB容器已经在运行,咱们建立web容器的时候引用这个DB容器,给它起一个别名叫作dbapp,那么在这个新建的web容器中,咱们能够在任什么时候候使用主机名dbapp和DB通讯
docker的两样法宝
Cgroups
做用:
限制linux进程组的资源占用
为进程组制做PIDS,UTS,IPC,网络和装载命名空间
Cgroup建立一个环境,进程能够在其中运行,并与操做系统的其余进程进行隔开
容器runtime是容器真正运行的地方,runtime须要和操做系统kernel紧密结合,为容器提供运行环境。
好比说,java程序比做一个容器,JVM就是runtime。JVM为java程序提供运行环境。
因此容器只能在runtime里面运行
lxc、runc 和 rkt 是目前主流的三种容器 runtime。
lxc 是 Linux 上老牌的容器 runtime。Docker 最初也是用 lxc 做为 runtime。
runc 是 Docker 本身开发的容器 runtime,符合 oci 规范,也是如今 Docker 的默认 runtime。
rkt 是 CoreOS 开发的容器 runtime,符合 oci 规范,于是可以运行 Docker 的容器。
除了运行环境,使用者也得须要工具来管理容器。容器管理工具对内与runtime交互,对外为用户提供interface.
lxd是lxc对应的容器管理工具;runc的管理工具是docker engine。docker engine 包含后台 deamon 和 cli 两个部分。咱们一般提到 Docker,通常就是指的 docker engine。rkt 的管理工具是 rkt cli。
容器定义工具容许用户定义容器的内容属性,这样容器就可以被保存,共享和重建
docker image 是 docker 容器的模板,runtime 依据 docker image 建立容器。
dockerfile 是包含若干命令的文本文件,能够经过这些命令建立出 docker image。
ACI (App Container Image) 与 docker image 相似,只不过它是由 CoreOS 开发的 rkt 容器的 image 格式。
容器是经过image建立的,须要一个仓库统一存放image,这个仓库就叫作Registy
企业能够用 Docker Registry 构建私有的 Registry。
Docker Hub(https://hub.docker.com )是 Docker 为公众提供的托管 Registry,上面有不少现成的 image,为 Docker 用户提供了极大的便利。
Quay.io(https://quay.io/ )是另外一个公共托管 Registry,提供与 Docker Hub 相似的服务。
由于容器有runtime,因此几乎全部的linux、MAC OS和windows均可以运行容器
容器 OS 是专门运行容器的操做系统。与常规 OS 相比,容器 OS 一般体积更小,启动更快。由于是为容器定制的 OS,一般它们运行容器的效率会更高。
目前已经存在很多容器 OS,CoreOS、atomic 和 ubuntu core 是其中的杰出表明。
容器核心技术可以让让容器在单个主机上运行,容器平台技术可以让容器做为集群在分布式环境中运行。容器平台技术以下图:
分为容器编排技术、容器管理平台、基于容器的PaaS。
基于容器的应用通常会采用微服务架构。在这中间架构下,应用被划分红不一样的组件,并以服务的方式运行在各个容器中,经过API对外提供服务,为了保证服务的高可用,每一个组件会运行多个相同的容器。
这些容器会组成集群,集群中的容器会根据业务动态的建立、迁移和销毁。
这样基于微服务架构的系统其实是一个动态可伸缩的系统。容器编排引擎就排上用场了。
编排(orchestration),一般包括容器管理、调度、集群定义和服务发现。经过容器编排引擎、容器被有机的组合成微服务应用,实现业务需求。
docker swarm 是 Docker 开发的容器编排引擎。
kubernetes 是 Google 领导开发的开源容器编排引擎,同时支持 Docker 和 CoreOS 容器。
mesos 是一个通用的集群资源调度平台,mesos 与 marathon 一块儿提供容器编排引擎功能。
以上三者是当前主流的容器编排引擎。
容器管理平台是在容器编排引擎之上的一个更为通用的平台。一般容器管理平台可以支持多个编排引擎,抽象了编排引擎的底层实现细节。
好比:application catalog和一键应用部署
Rancher和Containership是容器管理平台的典型表明
容器使得网络变得复杂,用户须要专门的解决方案来管理容器与容器,容器与其余实体之间的连通性和隔离性。
docker network是docker原生的解决方案。
微服务的最大特色是动态变化,当负载增长时,集群会自动建立新的容器;负载减少,多余的容器就会被销毁。容器也会根据主机的资源状况在不一样主机上迁移,容器的IP和端口也随之改变。
在这种状况下,必需要让客户端可以知道如何访问容器提供的服务。这就是服务发现的工做。
服务发现会保存集群中全部微服务的最新信息,好比IP和端口,对外提供的API,提供服务和查询等。
比较主流的是etcd,consul,zookeeper。
制做第一个容器
1.一个Ubuntu系统
2.这个系统可以联网,最起码ping www.baidu.com是能够的
这些准备条件准备好了,接下来就开始作准备工做。
Docker 分为开源免费的 CE(Community Edition)版本和收费的 EE(Enterprise Edition)版本。下面咱们将按照文档,经过如下步骤在 Ubuntu 16.04 上安装 Docker CE 版本。
这里下载的是CE版本。
打开ubuntu虚拟机,ping 一下百度
OK,能够的,由于制做容器的过程当中须要联网,这个条件是必要的。
1.安装包,容许 apt
命令 HTTPS 访问 Docker 源。执行命令:
sodo apt-get install apt-transport-https ca-certificate curl software-properties-common
而后会下载一些东西,等待下载完成便可
2.添加 Docker 官方的 GPG
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
3.将Docker的源添加到/etc/apt/source.list
sodu add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
4.刷新apt源
sudo apt-get update
5.安装Docker
sudo apt-get install docker-ce
这步完成以后,Docker也就安装完成了,是否是很简单,接下来就是如何使用Dokcer的问题了。
下载你的第一个容器:
docker run -d -p 80:80 httpd
这个过程是,首先docker发现主机上没有http,而后就会去下载(镜像中已经安装好了 Apache HTTP Server),下载完毕以后再运行运行,将容器的80端口映射到主机的80端口。
接下来检测一下容器是否正常运行,浏览器中输入该主机的IP,我这里是192.168.90.71
OK,web服务器运行成功!
Docker的第一个helloworld也就大功告成!
容器是一个自包含,可移植,轻量级的软件打包技术。是应用程序在任何地方几乎以相同方式运行。开发人员在开发机上建立好容器,无需任何修改就能在虚拟机,云服务器或公有云主机上运行。
容器有两部分组成:
1.应用程序自己
2.应用程序所依赖的环境,库
容器在主机中运行,与操做系统中其余的进程隔离,这一点区别于虚拟机。
传统的虚拟机技术,如:vmvare,他是建立一个完整的虚拟机,为了运行应用程序,部署系统,还须要安装整个操做系统(几十GB),
下图展现了二者的区别:
从右图中能够看见,全部容器都共享一个系统,对于虚拟机来讲,都是一个单独的系统。
启动容器不须要启动整个系统,因此容器部署和启动速度更快,开销更小,也更容易迁移。
由于方便。这取决于容器使得软件具有超强的可移植能力。
现现在软件开发的部署相对于之前来讲,要复杂不少,开发人员须要使用多种服务构建和组装应用,并且系统还可能会部署到不一样的环境中。
并且这个服务都有本身依赖的库和环境,还有可能存在着动态迁移到不一样的环境中。
你们作过软件开发的都知道,软件部署是一件很麻烦的事情,那么有没有一种技术使得软件部署很平滑呢?
开发人员受到了集装箱的启发。
之前运送货物,会担忧货物类型不一样而担忧损失,好比运送的食物被其余货物压坏了。后来人们发明了集装箱,标准集装箱能够被高效地装卸、重叠和长途运输。现代化的起重机能够自动在卡车、轮船和火车之间移动集装箱。集装箱被誉为运输业与世界贸易最重要的发明。
Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。Docker 能够将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器能够运行在几乎全部的操做系统上。
容器意味着环境隔离和可重复性。开发人员只需为应用建立一次运行环境,而后打包成容器即可在其余机器上运行。另外,容器环境与所在的 Host 环境是隔离的,就像虚拟机同样,但更快更简单。
Docker的核心组件:
1.Docker客户端 - Client
2.Docker服务器 - Docker deamon
3.Docker镜像 - Image
4.仓库 - Registry
5.Docker容器 - Container
Docker架构图以下:
Docker采用的是C/S架构,客户端向服务器发送请求,服务器负责建立、运行和分发容器。
Docker客户端的命令以下:
Docker deamon是服务器组件,以Linux后台服务方式运行。
Docker daemon 运行在 Docker host 上,负责建立、运行、监控容器,构建、存储镜像。
默认配置下,Docker daemon 只能响应来自本地 Host 的客户端请求。若是要容许远程客户端请求,须要在配置文件中打开 TCP 监听,步骤以下:
1.编辑配置文件 /etc/systemd/system/multi-user.target.wants/docker.service,在环境变量 -H tcp://0.0.0.0
,容许来自任意 IP 的客户端链接。
2.重启 Docker daemon。
3.服务器 IP 为 192.168.56.102,客户端在命令行里加上 -H 参数,便可与远程服务器通讯
可将Docker镜像当作一个只读模板。一个镜像里可能含有一个系统,或者一个Tomcat。
镜像有多种生成方法:
能够从无到有开始建立镜像
也能够下载并使用别人建立好的现成的镜像
还能够在现有镜像上建立新的镜像
咱们能够将镜像的内容和建立步骤描述在一个文本文件中,这个文件被称做 Dockerfile,经过执行 docker build <docker-file>
命令能够构建出 Docker 镜像。
Docker容器就是Docker运行的环境。对于软件而言,镜像像是生命周期的构建和打包阶段,容器则是启动和运行阶段。
镜像有多种生成方法:
能够从无到有开始建立镜像
也能够下载并使用别人建立好的现成的镜像
还能够在现有镜像上建立新的镜像
咱们能够将镜像的内容和建立步骤描述在一个文本文件中,这个文件被称做 Dockerfile,经过执行 docker build <docker-file>
命令能够构建出 Docker 镜像.
docker pull 命令是从Registry下载镜像
docker run命令是先下载镜像 而后再启动容器
下面看一个运行实例:
Docker 客户端执行 docker run
命令。
Docker daemon 发现本地没有 httpd 镜像。
daemon 从 Docker Hub 下载镜像。
下载完成,镜像 httpd 被保存到本地。
Docker daemon 启动容器。
docker images 能够看下已经下载到本地的镜像。
dokcer ps 能够查看哪些容器正在运行
镜像的分层结构:
实际上,Docker Hub 中 99% 的镜像都是经过在 base 镜像中安装和配置须要的软件构建出来的。好比咱们如今构建一个新的镜像,Dockerfile 以下:
① 新镜像再也不是从 scratch 开始,而是直接在 Debian base 镜像上构建。
② 安装 emacs 编辑器。
③ 安装 apache2。
④ 容器启动时运行 bash。
构建过程以下图所示:
能够看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增长一层。
问什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是 - 共享资源。
好比:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就能够为全部容器服务了。并且镜像的每一层均可以被共享,咱们将在后面更深刻地讨论这个特性。
这时可能就有人会问了:若是多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,好比 /etc 下的文件,这时其余容器的 /etc 是否也会被修改?
答案是不会!
修改会被限制在单个容器内。由于容器的Copy-on-Write特性
可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层一般被称做“容器层”,“容器层”之下的都叫“镜像层”。
全部对容器的改动 - 不管添加、删除、仍是修改文件都只会发生在容器层中。
添加文件
在容器中建立文件时,新文件被添加到容器层中。
读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,当即将其复制到容器层,而后打开并读入内存。
修改文件 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,当即将其复制到容器层,而后修改之。
删除文件 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操做。
只有当须要修改时才复制一份数据,这种特性被称做 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像自己进行任何修改。
这样就解释了咱们前面提出的问题:容器层记录对镜像的修改,全部镜像层都是只读的,不会被容器修改,因此镜像能够被多个容器共享。
使用现成镜像的好处除了省去本身作镜像的工做量外,更重要的是能够利用前人的经验。特别是使用那些官方镜像,由于 Docker 的工程师知道如何更好的在容器中运行软件。
固然,某些状况下咱们也不得不本身构建镜像,好比:
找不到现成的镜像,好比本身开发的应用程序。
须要在镜像中加入特定的功能,好比官方镜像几乎都不提供 ssh。
因此本节咱们将介绍构建镜像的方法。同时分析构建的过程也可以加深咱们对前面镜像分层结构的理解。
Docker 提供了两种构建镜像的方法:
docker commit 命令
Dockerfile 构建文件
Docker官方推荐使用Dockerfile构建镜像。
Docker 会缓存已有镜像的镜像层,构建新镜像时,若是某镜像层已经存在,就直接使用,无需从新建立。
Dockerfile 中每个指令都会建立一个镜像层,上层是依赖于下层的。不管何时,只要某一层发生变化,其上面全部层的缓存都会失效。
也就是说,若是咱们改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。
Dockerfile指令说明 |
||
指令 |
说明 |
用法 |
FROM |
指定base镜像 |
两种用法: 1.FROM <image> 指定基础image为该image的最后修改的版本 2.FROM <image>:<tag> 指定基础image为该image的一个tag版本。 |
MAINTAINER |
设置镜像的做者,用于将image的制做者相关的信息写入到image中 |
MAINTAINER <name> |
RUN |
在容器中运行制定的命令, 通常用于装软件 |
两种格式: 1.RUN <command> (the command is run in a shell - `/bin/sh -c`) 2.RUN ["executable", "param1", "param2" ... ] (exec form) |
CMD |
(设置container启动时执行的操做) |
三种方式
第三种方式:当指定了ENTRYPOINT,那么使用下面的格式 CMD ["param1","param2"] (as default parameters to ENTRYPOINT) |
ENTRYPOINT |
配置容器启动后执行的命令,而且不可被 docker run 提供的参数覆盖。
每一个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。 |
ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form) ENTRYPOINT command param1 param2 (as a shell) 该指令的使用分为两种状况,一种是独自使用,另外一种和CMD指令配合使用。
当独自使用时,若是你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。 # CMD指令将不会被执行,只有ENTRYPOINT指令被执行 CMD echo “Hello, World!” ENTRYPOINT ls -l
另外一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。 FROM ubuntu CMD ["-l"] ENTRYPOINT ["/usr/bin/ls"] |
EXPOSE |
设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你须要访问容器的时候,能够不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操做须要两个步骤,首先在Dockerfile使用EXPOSE设置须要映射的容器端口,而后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。 |
EXPOSE <port> [<port>...] |
ENV |
用于设置环境变量 |
设置了后,后续的RUN命令均可以使用,容器启动后,能够经过docker inspect查看这个环境变量,也能够经过在docker run --env key=value时设置或修改环境变量。 假如你安装了JAVA程序,须要设置JAVA_HOME,那么能够在Dockerfile中这样写: ENV JAVA_HOME /path/to/java/dirent |
ADD |
从src复制文件到容器的dest路径 若是是一个目录,那么会将该目录下的全部文件添加到容器中,不包括目录;若是文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式) |
ADD <src> <dist> <src>是相对被构建的源目录的相对路径,能够是文件或目录的路径,也能够是一个远程的文件url; <dist>是容器的绝对路径 |
VOLUMN |
设置指令,使容器中的一个目录具备持久化存储数据的功能,该目录能够被容器自己使用,也能够共享给其余容器使用。咱们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,全部的更改都会丢失。当容器中的应用有持久化数据的需求时能够在Dockerfile中使用该指令。 |
VOLUME ["<mountpoint>"] 例: FROM unbuntu VOLUMN [“/tmp/data”]运行经过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。
|
WORKDIR
|
能够屡次切换(至关于cd命令),对RUN,CMD,ENTRYPOINT生效。 |
例:# 在 /p1/p2 下执行 vim a.txt WORKDIR /p1 WORKDIR p2 RUN vim a.txt |