Docker 概述
- Docker 是一个开源的应用容器引擎,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目,它基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于 go语言并遵从 Apache2.0 协议开源
- Docker让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。可以徆容易地在机器和数据中心中运行。最重要的是,他们不依赖于任何语言、框架或包装系统,几乎没有性能开销,docker 镜像一次编译,到处运行。
- Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持Docker;Google 也在其 PaaS 产品中广泛应用。
- Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单
- LXC 为 Linux Container 的简写。 Linux Container 容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,而且丌需要提供挃令解释机制以及全虚拟化的其他复杂性。
- LXC 主要通过来自 kernel 的 namespace 实现每个用户实例之间的相互隔离,通过 cgroup 实现对资源的配额和度量。
官方网站:https://www.docker.com/
源代码下载:https://github.com/docker/docker
Docker 容器技术与虚拟机对比
相同点: docker 容器技术和虚拟机技术,都是虚拟化技术。
不同点:docker相对于VM虚拟机,少了虚拟机操作系统这一层,所以docker效率比虚拟机高,在docker上启动一个实例 1-2秒
对比传统虚拟机总结:
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
为什么要使用 Docker
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
具体说来,Docker 在如下几个方面具有较大的优势。
- 更快速的交付和部署
对开发和运维(devop)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。 Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。
- 更高效的虚拟化
Docker 容器的运行不需要额外的 hypervisor 支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。
- 更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
- 更简单的管理
使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。
Docker 架构
工作流程:
服务器 A 上运行 docker Engine 服务,在 docker Engine 上启劢徆多容器 container ,从外网 Docker Hub 上把 image 操作系统镜像下载来,放到 container 容器运行。 这样一个容器的实例就运行起来了。最后,通过 Docker client 对 docker 容器虚拟化平台进行控制。
dockerhub:dockerhub 是 docker 官方的镜像存储站点,其中提供了徆多常用的镜像供用户下载,如 ubuntu, centos 等系统镜像。通过 dockerhub 用户也可以发布自己的 docker 镜像,为此用户需要注册一个账号,在网站上创建一个 docker 仓库。
Docker 包括三个基本概念
- 镜像(Image)
- 容器(Container)
- 仓库(Repository)
理解了这三个概念,就理解了 Docker 的整个生命周期。
1. Docker 镜像
- Docker 镜像就是一个只读的模板。 例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。镜像可以用来创建 Docker 容器。
- Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
- 因为镜像包含操作系统完整的root文件系统,其体积往往是庞大的,因此在Docker设计时将其设计为分层存储的架构。镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
- 镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生再自己这一层。在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
- 分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需要的内容,构建新的镜像。
2. Docker 容器
- Docker 利用容器来运行应用。
- 容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
- 可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
- 镜像使用的是分层存储,容器也是如此。每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。
- 容器存储层的生命周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
- 按照Docker最佳实践的要求,容器不应该向其存储内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用Volume数据卷、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
- 数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,在使用数据卷后,容器删除或者重新运行之后,数据却不会丢失
注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
3. Docker 仓库
- 仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
- 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
- 最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。 国内的公开仓库包括 Docker Pool等,可以提供大陆用户更稳定快速的访问。当然,用户也可以在本地网络内创建一个私有仓库。
- 当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
4. Docker Registry公开仓库
- 常用的Registry是官方的Docker Hub,这也是默认的Registry。除此之外,还有CoreOS的Quay.io,CoreOS相关的镜像存储在这里;Google的Google Container Registry,Kubernetes的镜像使用的就是这个服务。
- 国内的一些云服务商提供了针对Docker Hub的镜像服务,这些镜像服务被称为加速器。常见的有阿里云加速器、DaoCloud加速器等。使用加速器会直接从国内的地址下载Docker Hub的镜像,比直接从Docker Hub下载速度会提高很多。
- 国内也有一些云服务上提供类似于Docker Hub的公开服务。比如网易云镜像服务、DaoCloud镜像市场、阿里云镜像库等。
5. Docker Registry 私有仓库
- 除了使用公开服务外,用户还可以在本地搭建私有Docker Registry。Docker官方提供了Docker Registry镜像,可以直接使用作为私有Registry服务。
- 开源的Docker Registry镜像只提供了Docker Registry API的服务端实现,足以支持docker命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本Docker Trusted Registry中,提供了这些高级功能。
- 除了官方的Docker Registry外,还有第三方软件实现了Docker Registry
API,甚至提供了用户界面以及一些高级功能。比如,VMWare Harbor和Sonatype Nexus。
注:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为GitHub 这样的托管服务。
Docker 核心技术:
- Namespace — 实现 Container 的进程、网络、消息、文件系统和主机名的隔离。
- Cgroup — 实现对资源的配额和度量。 注:Cgroup 的配额,可以挃定实例使用的 cpu 个数,内存大小等。 就像如下图,vmware 虚拟机中的硬件配置参数。
Docker 特性:
- 文件系统隔离:每个进程容器运行在一个完全独立的根文件系统里。
- 资源隔离:系统资源,像 CPU 和内存等可以分配到丌同的容器中,使用 cgroup。
- 网络隔离:每个进程容器运行在自己的网络空间,虚拟接口和 IP 地址。
- 日志记彔:Docker将会收集和记彔每个进程容器的标准(stdout/stderr/stdin),用于实时检索或批量检索。
- 变更管理:容器文件系统的变更可以提交到新的镜像中,并可重复使用以创建更多的容器。无需使用模板或手劢配置。
- 交互式 shell:Docker 可以分配一个虚拟终端并关联到任何容器的标准输入上,例如运行一个一次性交互 shell。
Docker优点:
- 一些优势和 VM 一样,但不是所有都一样。比 VM 小,比 VM快,Docker 容器的尺寸减小相比整个虚拟机大大简化了分布到云和从云分发时间和开销。 Docker 启劢一个容器实例时间徆短,一两秒就可以启劢一个实例。
- 对于在笔记本电脑,数据中心的虚拟机,以及任何的云上,运行相同的没有变化的应用程序,IT 的发布速度更快。 Docker 是一个开放的平台,构建,发布和运行分布式应用程序。 Docker 使应用程序能够快速从组件组装和避免开发和生产环境乊间的摩擏。
- 您可以在部署在公司局域网或云或虚拟机上使用它。
- 开发人员并丌关心具体哪个 Linux 操作系统使用 Docker,开发人员可以根据所有依赖关系构建相应的软件,针对他们所选择的操作系统。然后,在部署时一切是完全一样的,因为一切都在DockerImage 的容器在其上运行。开发人员负责并且能够确保所有的相关性得到满足。
- Google,微软,亚马逊,IBM 等都支持 Docker。
- Docker 支持 Unix/Linux 操作系统,也支持 Windows 或 Mac
Docker缺点局限性:
- Docker 用于应用程序时是最有用的,但并丌包含数据。日志,跟踪和数据库等通常应放在 Docker容器外。 一个容器的镜像通常都徆小,丌适合存大量数据,存储可以通过外部挂载的方式使用。比如使用:NFS,ipsan,MFS 等, -v 映射磁盘分区
- 一句话:docker 叧用于计算,存储交给别人。
- oracle 不适合使用 docker 来运行,太大了,存储的数据太多。
实验环境准备
实验环境: CENTOS7.5 64 位
Docker在1.13版本之后,从2017年的3月1日开始,版本命名规则变为如下
项目 | 说明 |
---|---|
版本格式 | YY.MM |
Stable版本 | 每个季度发行 |
Edge版本 | 每个月发行 |
当前Docker CE Stable版本 | 19.03 |
当前Docker CE Edge版本 | 19.03 |
docker 主要有两个发行版本:docker.io(基于 centos 版本的 docker)和 docker-engine(基于ubuntu 版本的 docker);docker-ce 版本是 docker.io 的社区版本,同时Docker划分为CE和EE。CE即社区版(免费,支持周期三个月),EE即企业版,强调安全,付费使用。
安装需求
Docker支持 64 位版本CentOS 7,并且要求内核版本不低于3.10
官方网站上有各种环境下的安装指南,
官方安装指南地址:https://docs.docker.com/install/
卸载旧版本
- 旧版本的Docker称为docker或者docker-engine,使用以下命令卸载旧版本:
[root@xuex ~]# yum remove docker docker-common docker-selinux docker-engine
Docker安装
方法一:本地上传Docker软件编译安装包进行安装
- 下载docker离线安装包,需要通过yum的离线下载命令进行
[root@xuex ~]# yum install --downloadonly --downloaddir=/docker/dockerRpm docker
- 拷贝下载的rpm包到安装docker的机器上面,然后解压
[root@docker ~]# tar zxvf docker-rpm.tar.gz -C /docker-rpm
- 配置本地 yum 源
[root@docker ~]# vim /etc/yum.repos.d/docker-rpm.repo
[Docker-install]
name=Docker
baseurl=file:///docker-rpm
enable=1
gpgcheck=0
[root@docker ~]# createrepo -d /docker-rpm/
- 安装Docker
[root@docker ~]# yum -y install docker
[root@docker ~]# systemctl start docker
[root@docker ~]# systemctl enable docker
[root@docker ~]# docker version
Client:
Version: 1.13.1
API version: 1.26
Package version: docker-1.13.1-103.git7f2769b.el7.centos.x86_64
Go version: go1.10.3
Git commit: 7f2769b/1.13.1
Built: Sun Sep 15 14:06:47 2019
OS/Arch: linux/amd64
Server:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Package version: docker-1.13.1-103.git7f2769b.el7.centos.x86_64
Go version: go1.10.3
Git commit: 7f2769b/1.13.1
Built: Sun Sep 15 14:06:47 2019
OS/Arch: linux/amd64
Experimental: false
查看 docker 信息(确认服务运行)显示 Docker 系统信息,包括镜像和容器数。
[root@hama63 docker]# docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
.............
Network: bridge host macvlan null overlay
.............
Profile: /etc/docker/seccomp.json
............
Docker Root Dir: /var/lib/docker #默认的 docker 的家目彔
.............
Registry Mirrors:
https://registry.docker-cn.com #默认的 dockerhub 的镜像源
............
方法二:直接使用 centos 系统自带的 yum 源安装
[root@docker ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
[root@docker ~]# yum -y install docker-ce
[root@docker ~]# systemctl start docker
[root@docker ~]# systemctl enable docker
注:如果安装的是centos7 minimal版本,执行安装提示“没有可用软件包”。这个时候需要安装必要的软件依赖以及更新增加docker-ce yum源。
[root@docker ~]# yum install -y yum-utils device-mapper-persistent-data lvm2
注:如果提示没有yum-config-manager命令,执行yum -y install yum-utils 安装即可,然后再执行一次上面的命令
[root@docker ~]# yum -y install yum-utils
方法三:使用脚本安装
在测试或开发环境中Docker官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS系统上可以使用这套脚本安装:
[root@docker ~]# curl -fsSL https://get.docker.com -o get-docker.sh
[root@docker ~]# chmod 777 get-docker.sh
[root@docker ~]# sh get-docker.sh --mirror Aliyun
[root@docker ~]# systemctl start docker
[root@docker ~]# systemctl enable docker
建立docker用户组
默认情况下,docker命令会使用Unix socket与Docker引擎通讯。而只有root用户和docker组的用户才可以访问Docker引擎的Unix Socket。一般Linux系统上不会直接使用root用户进行操作。因此,需要使用docker的用户加入docker用户组。
[root@docker ~]# groupadd docker #建立docker组
[root@docker ~]# usermod -aG docker $USER #将当前用户加入docker组
删除Docker
[root@docker ~]# sudo yum remove docker-ce #删除docker-ce
[root@docker ~]# rm -rf /var/lib/docker #删除docker镜像
配置docker加速镜像
默认docker镜像是从国外的源下载,这样就会造成在pull镜像的时候,经常会因为网络问题,造成pull失败。所以我们配置国内的docker镜像加速源,一般使用阿里云、网易163等常用的网络源。
例如:
- Docker官方提供的中国Registry mirror
- 阿里云加速器
- DaoCloud加速器
- 163加速器
如下:以阿里云加速器为例进行介绍
[root@docker]# tee /etc/docker/daemon.json << eof
{
"registry-mirrors":["https://sw7q7k1w.mirror.aliyuncs.com"]
}
eof
[root@docker]# systemctl daemon-reload
[root@docker]# systemctl restart docker
Docker常用命令
命令官方参考手册
地址:https://docs.docker.com/engine/reference/commandline
- 下载 docker 镜像
从Docker镜像仓库获取镜像的命令是docker pull。其命令格式为:
docker pull[选项][Docker Registry 地址[:端口号]/]仓库名[:标签]
具体的选项可以通过docker pull --help命令看到,这里我们说一下镜像名称的格式。
- Docker镜像仓库地址:地址的格式一般是<域名/IP>[:端口号]。默认地址是Docker Hub。
- 仓库名:仓库名是两段式名称,即<用户名>/<软件名>。
- 对于Docker Hub,如果不给出用户名,则默认为library,也就是官方镜像。
例如:
[root@docker ~]# docker pull centos:7.5.1804
- 运行镜像
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以centos:7.5.1804为例,如果我们打算启动里面的bash并且进行交互式操作的话,可以执行:
[root@docker ~]# docker run -it --rm centos:7.5.1804 bash
- -it:这是两个参数,一个是 -i:交互式操作,一个是 -t:终端。
- –rm:这个参数是说容器退出后随之将其删除。
- centos:7.5.1804: 这是指用centos:7.5.1804镜像为基础来启动容器。
- bash:放在镜像名后的是命令,这里我们希望有个交互式Shell,因此用的是bash。最后通过exit指令退出这个容器。
- –name参数可以指定容器的名称
- -p [宿主机端口号]:[容器端口号],该命令可以用来将容器的端口映射到宿主机的端口
- 显示镜像
- 列出已经下载下来的镜像,可以使用docker images ls命令。列表包含了仓库名、标签、镜像ID、创建时间以及所占用的空间
[root@docker ~]# docker image ls
或者
[root@docker ~]# docker images
示例:
[root@docker ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 16.04 56bab49eef2e 2 weeks ago 123MB
centos 7.5.1804 cf49811e3cdb 9 months ago 200MB
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 16.04 56bab49eef2e 2 weeks ago 123MB
centos 7.5.1804 cf49811e3cdb 9 months ago 200MB
[root@docker ~]# docker image ls -f dangling=true #显示虚悬镜像(dangling image),即:仓库名、标签均为<none>的镜像
- 查看镜像、容器、数据卷所占用的空间
[root@docker ~]# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 322.2MB 322.2MB (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
- 删除镜像
要删除本地的镜像,可以使用docker image rm命令,其格式为:
docker image rm [OPTIONS] IMAGE [IMAGE...]
- –force , -f Force removal of the image
- –no-prune Do not delete untagged parents
其中,可以是镜像短ID、镜像长ID、镜像名或者镜像摘要。
另外,使用docker image ls -q来配合docker image rm,这样可以批量删除希望删除的镜像,格式如下:
docker image rm $(docker image ls -q centos) #删除所有仓库名为centos的镜像
docker image rm $(docker image ls -q -f before=centos:7.5.1804) #删除所有在centos:7.5.1804之前的镜像
- Docker容器操作
容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。
启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。因为Docker的容器是轻量级的,用户可以随时删除和新创建容器。
- 新建并启动
使用 docker run 命令启动, 例如输出一个“Hello World”,之后终止容器。
[root@docker ~]# docker run centos:7.5.1804 /bin/echo 'hello world'
hello world
- 启动已终止容器
使用 docker container start 或者 docker start命令, 例如:启动一个bash终端,允许用户进行交互。
[root@docker ~]# docker run -t -i centos:7.5.1804 /bin/bash
Option:
-t 让Docker分配一个伪终端并绑定到容器的标准输入上,-i 则让容器的标准输入保持打开。也可以合并 -it,当利用docker run来创建容器时,Docker在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从共有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个ip地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
- 后台运行
很多时候,需要让Docker在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时可以通过添加 -d 参数来实现。如果不使用 -d 参数运行容器,比如 docker run hello-world 会把日志打印在控制台;如果使用了 -d 参数运行容器,比如 docker run -d hello-world 不会输出日志,只会打印容器id(输出结果可以用 docker logs [容器长id] 查看)
注:容器是否会长久运行,是和docker run 指定的命令有关, 和 -d 参数无关。
- 停止运行的容器
- 可以使用 docker container stop 来终止一个运行中的容器。
- 终止状态的容器可以用 docker container ls -a 命令看到。
- 处于终止状态的容器,可以通过 docker container start 命令来重新启动。docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。
- 进入容器
docker exec -it 容器ID /bin/bash
- 在使用 -d 参数时,容器启动后会进入后台,某些时候需要进入容器进行操作,使用 docker exec 命令可以进入到运行中。
- exec 命令 -i -t 参数
- 只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的Linux命令提示符,但命令执行结果仍然可以返回。
- 当 -i -t参数一起使用时,则可以看到Linux命令提示符。
4)导出和导入容器
- 导出容器
导出本地某个容器,可以使用 docker export 命令。如下所示:
docker export IMAGEID > 导出文件名.zip
- 导入容器
[root@docker ~]# docker load -i /root/docker.io-centos.tar
也可以使用 docker import从容器快照文件中再导入为镜像
docker import : 从归档文件中创建镜像。语法如下:
docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
OPTIONS说明:
-c :应用docker 指令创建镜像;
-m :提交时的说明文字;
举例说明:
cat 导出文件名.zip | docker import - 镜像用户/镜像名:镜像版本
此外,也可以通过制定URL或者某个目录来导入
[root@docker ~]# docker import http://hub.c.163.com/public/centos:6.7-tools
- 删除单个容器
可以使用docker container rm来删除一个处于终止状态的容器。
[root@docker ~]# docker container rm centos:7.5.1804
如果要删除一个运行中的容器,可以添加 -f 参数。Docker会发送 SIGKILL 信号给容器。
[root@docker ~]# docker container rm -f centos:7.5.1804
- 清理所有处于终止状态的容器
用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,
用下面的命令可以清理掉所有处于终止状态的容器。
[root@docker ~]# docker container prune
利用Dockerfile构建私有镜像
使用Dockerfile定制镜像
使用docker build创建镜像时,需要使用Dockerfile文件自动化制作image镜像,镜像的定制实际上就是定制每一层所添加的配置、文件。我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,这个脚本就是Dockerfile。Dockerfile是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
注:Dockerfile有点像源码编译时./configure后产生的Makefile
下面以官方http镜像为例,使用Dockerfile来定制。
1. 创建工作目录
[root@docker ~]# mkdir /docker-build
[root@docker ~]# cd /docker-build/
[root@docker docker-build]# touch Dockerfile //注: make自动化编译时需要Makefile文件,自动化创建docker镜像时,需要Dockerfile
2、编辑 Dockerfile
[root@docker docker-build]# vim Dockerfile
内容如下:
FROM docker.io/centos:latest # FROM 基于哪个镜像
MAINTAINER <docker@zhizuo> # MAINTAINER 镜像创建者
RUN yum -y install httpd #RUN 安装软件用
ADD start.sh /usr/local/bin/start.sh
ADD index.html /var/www/html/index.html
CMD /usr/local/bin/start.sh
# ADD 将文件<src>拷贝到新产生的镜像的文件系统对应的路径<dest>。所有拷贝到新镜像中的文件和文件夹权限为0755,uid和gid为0
CMD echo hello world #container启动时执行的命令或启动服务,但是一个Dockerfile中只能有一条CMD命令,多条则只执行最后一条CMD.
3、创建 start.sh脚本启动httpd服务和apache默认首页index.html文件
[root@docker docker-build]# echo "/usr/sbin/httpd -DFOREGROUND" > start.sh
[root@docker docker-build]# chmod +x start.sh
[root@docker docker-build]# echo "docker image build test" > index.html
4、使用命令build来创建新的image
[root@docker docker-build]# docker build -t docker.io/centos:httpd ./
[root@docker docker-build]# docker images
[root@docker docker-build]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
cnetos httpd cb3dea23c570 3 minutes ago 269MB
ubuntu 16.04 56bab49eef2e 3 weeks ago 123MB
nginx latest 231d40e811cd 4 weeks ago 126MB
centos latest 0f3e07c0138f 2 months ago 220MB
centos 7.5.1804 cf49811e3cdb 9 months ago 200MB
Dockerfile指令详解
我们已经介绍了FROM,RUN,其实Dockerfile功能很强大,他提供了十多个指令。
- COPY复制文件
格式:
COPY<源路径>…<目标路径>
COPY["<源路径1>",…,"<目标路径>"]
COPY指令将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置。
比如:
COPY package.json /usr/src/app/
<源路径>可以是多个,甚至可以是通配符,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
- ADD更高级的复制文件
ADD指令和COPY的格式和性质基本一致。但是在COPY基础上增加了一些功能。
比如<源路径>可以是一个URL,这种情况下,Docker引擎会去下载这个链接的文件放到<目标路径>去。
在Docker官方的Dockerfile最佳实践文档中要求,尽可能的使用COPY,因为COPY的语义很明确,就是复制文件而已,而ADD则包含了更复杂的功能,其行为也不一定很清晰。最适合使用ADD的场合,就是所提及的需要自动解压缩的场合。
因此在COPY和ADD指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY指令,仅在需要自动解压缩的场合使用ADD。
- CMD容器启动命令
CMD指令的格式和RUN相似,也是两种格式:
shell格式:CMD<命令>
exec格式:CMD [“可执行文件”,“参数1”,“参数2”…]
参数列表格式: CMD [“参数1”,“参数2”…]。指定了ENTRYPOINT指令后,用CMD指定具体的参数。
Docker不是虚拟机,容器就是进程。既然是进程,name在启动容器的时候,需要指定所运行的程序及参数。CMD指令就是用于指定默认的容器主进程启动命令的。
- ENTRYPOINT入口点
ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数。ENTRYPOINT在运行时也可以替代,不过比CMD要略显繁琐,需要通过docker run的参数–entrypoint来指定
当指定了ENTRYPOINT后,CMD的含义就发生了改变,不再是直接的运行其命令,而是将CMD的内容作为参数传给ENTRYPOINT指令,换句话说实际执行时,将变为:<ENTRYPOINT> "<CMD>"
- ENV设置环境变量
格式有两种:
ENV <key><value>
ENV <key1>=<value1> <key2><value2>…
这个指令很简单,就是设置环境变量而已,无论是后面的其他指令,如RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"
$VERSION #使用环境变量,即可获得版本号
下面指令可以支持环境变量展开:ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD
- ARG构建参数
格式:
ARG <参数名>[=<默认值>]
构建参数和ENV的效果一样,都是设置环境变量。所不同的是,ARG所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用ARG保存密码之类的信息,因为docker history还是可以看到所有值的。
Dockerfile中ARG指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令docker build中用 --build-arg<参数名>=<值>来覆盖。
- VOLUME定义匿名卷
格式为:
VOLUME ["<路径1>","<路径2>"…]
VOLUME <路径>
容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(VOLUME)中,为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在Dockerfile中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会像容器存储层写入大量数据
VOLUME /data
这里的/data目录就会在运行时自动挂载为匿名卷,任何向/data中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:
docker run -d -v mydata:/data xxxx
在这行命令中,就使用了mydata这个命名卷挂载到了/data这个位置,替代了Dockerfile中定义的匿名的挂载配置。
- EXPOSE声明端口
格式为:
EXPOSE <端口1>[<端口2>…]
EXPOSE指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
在Dockerfile中写入这样的声明有两个好处:
1、帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
2、运行时随机端口映射时,也就是docker run -P时,会自动随机映射EXPOSE的端口。
- WORKDIR指定工作目录
格式为:
WORKDIR <工作目录路径>
使用WORKDIR指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR会帮你建立目录。
之前提到一些初学者常犯的错误是把Dockerfile等同于shell脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:
RUN cd /app
RUn echo "hello" > world.txt
如果将这个Dockerfile进行构建镜像运行后,会发现找不到/app/world.txt文件。
在Shell中,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令
而在Dockerfile中,这两行RUN命令的执行环境根本不同,是两个完全不同的容器。这就是对Dockerfile构建分层存储的概念不了解所导致的错误
每一个RUN都是启动一个容器、执行命令、然后提交存储层文件变更。
第一层RUN cd /app的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。
因此如果需要改变以后各层的工作目录的位置,那么应该使用WORKDIR指令。
- USER指定当前用户
格式为:
USER <用户名>
USER指令和WORKDIR指令相似,都是改变环境状态并影响以后的层。WORKDIR是改变工作目录,USER则是改变之后层的执行RUN,CMD以及ENTRYPOINT这类命令的身份。
当然,和WORKDIR一样,USER只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN ["redis-server"]
- HEALTHCHECK健康检查
格式为:
HEALTHCHECK [选项] CMD <用户名>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,可以屏蔽掉其健康检查指令
HEALTHCHECK指令是告诉Docker应该如何进行判断容器的状态是否正常,这是Docker1.12引入的新指令。通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。
一个镜像制定了HEALTHCHECK指令后,用其启动容器,初始状态会为starting,在执行健康检查成功后变为healthy,如果连续一定次数失败,则会变为unhealthy。
HEALTHCHECK支持下列选项:
1、–interval=<间隔>:两次健康检查的间隔,默认为30秒;
2、–timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认30秒;
3、–retries=<次数>:当连续失败指定次数后,则将容器状态视为unhealthy,默认3次。
为了帮助排障,健康检查命令的输出(包括stdout以及stderr)都会被存储于健康状态里,可以用docker inspect来查看。
- ONBUILD
格式为:
ONBUILD <其它指令>
ONBUILD是一个特殊的指令,它后边跟的是其它指令,比如RUN,COPY等。而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,区构建下一级镜像的时候才会被执行。
Dockerfile中的其它指令都是为了定制当前镜像而准备的,唯有ONBUILD是为了帮助别人定制自己而准备的。
Docker Image 的发布
方法1:Save Image To TarBall
语法:
docker save -o 导出的镜像名.tar 本地镜像名:镜像标签
示例:
[root@docker ~]# docker save -o docker.io-centos-httpd-docker-image.tar docker.io/centos:httpd
ls
Dockerfile docker.io-centos-httpd-docker-image.tar index.html start.sh
[root@docker docker-build]# ll
total 270876
-rw-r--r-- 1 root root 212 Dec 23 12:12 Dockerfile
-rw------- 1 root root 277364224 Dec 23 17:21 docker.io-centos-httpd-docker-image.tar
-rw-r--r-- 1 root root 24 Dec 23 12:13 index.html
-rwxr-xr-x 1 root root 29 Dec 23 12:12 start.sh
使用导入本地镜像
[root@docker docker-build]# docker rmi docker.io/centos:httpd
[root@docker docker-build]# docker load -i docker.io-centos-httpd-docker-image.tar
方法2:Push Image To Docker Hub 发布到外网
1.从加速器切换到仓库地址登录
docker login --username=账号 registry.cn-hangzhou.aliyuncs.com
2.根据镜像名字或者ID为它创建一个标签,缺省为latest
docker tag centos registry.cn-hangzhou.aliyuncs.com/hhu/docker1[:镜像版本号]
3.推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/hhu/docker1[:镜像版本号]
Java程序应用部署
1、准备一个定制镜像,把该war上传到安装有docker软件的服务器上宿主目录下。在同级目录下创建Dockerfile
[root@docker docker-build]# touch Dockerfile
[root@docker docker-build]# vim Dockerfile
按照前面章节所学的Dockerfile定制镜像知识来编写Dockerfile文件内容,文件内容如下:
#基础镜像使用tomcat:7.0.88-jre8
FROM tomcat:7.0.88-jre8
#作者(可选)
MAINTAINER <docker@zhizuo>
#定义环境变量
ENV TOMCAT_BASE /usr/local/tomcat
#复制war包
COPY ./test721.war $TOMCAT_BASE/webapps/
执行构建(放在当前目录.)
docker build -t session-webtest:latest .
如果构建成功,则会显示构建的分层信息及结果。
[root@docker docker-build]# docker build -t session-webtest:latest .
Sending build context to Docker daemon 280MB
Step 1/4 : FROM tomcat:7.0.88-jre8
---> 5ad66ba6af12
Step 2/4 : MAINTAINER <docker@zhizuo>
---> Using cache
---> c2ec540905a4
Step 3/4 : ENV TOMCAT_BASE /usr/local/tomcat
---> Using cache
---> 59a0bef0966e
Step 4/4 : COPY ./test721.war $TOMCAT_BASE/webapps/
---> Using cache
---> ea638c648c3d
Successfully built ea638c648c3d
Successfully tagged session-webtest:latest
构建成功后,使用docker images命令查看是否已经存在该镜像
2、运行镜像
镜像制作好之后我们就需要把它运行起来了
[root@docker docker-build]# docker run --name session-web -d -p 8800:8080 session-web:latest
#其中8800是宿主机的端口,8080是docker的端口
浏览器中访问 http://ip:8800/test721/index.jsp
搭建Docker私有仓库
1、Docker Hub
目前Docker官方维护了一个公共仓库Docker Hub,其中已经包括了数量超过15,000的镜像。大部分需求都可以通过在Docker Hub中直接下载镜像来实现。
2、注册登录及退出
可以在https://hub.docker.com免费注册一个Docker账号。
在命令行界面执行 docker login 输入用户名及密码来完成在命令行界面登录Docker Hub。可以通过 docker logout 退出登录
3、拉取镜像
可以通过 docker search 命令来查找官方仓库中的镜像,并利用docker pull命令来将它下载到本地。
4、推送镜像
用户也可以在登录后通过 docker push 命令来将自己的镜像推送到Docker Hub。
5、私有仓库
有时候使用Docker Hub这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。比如,基于公司内部项目构建的镜像。
docker-registry 是官方提供的工具,可以用于构建私有的镜像仓库。
6、安装运行docker-registry
可以通过获取官方registry镜像来运行。默认情况下,仓库会被创建在容器的== /var/lib/registry==目录下。
可以通过 -v 参数来将镜像文件存放在本地的指定路径。
[root@docker docker-build]# docker run --name registry -d -p 5000:5000 --restart=always -v /opt/data/registry:/var/lib/registry registry
7、在私有仓库上传、搜索、下载镜像
- 创建好私有仓库之后,就可以使用 docker tag 来标记一个镜像,然后推送它到仓库。现在本机查看已有的镜像命令:docker image ls
- 使用 docker tag 将session-web:latest这个镜像标记为127.0.0.1:5000/session-web:latest
格式为
docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
docker tag session-web:latest 127.0.0.1:5000/session-web:latest
- 使用 docker push 上传标记的镜像
docker push 127.0.0.1:5000/session-web:latest
- 用curl查看仓库中的镜像
curl 127.0.0.1:5000/v2/_catalog
注意:如果可以看到{“repositories”:[“session-web”]},表明镜像已经被成功上传了。
- 先删除已有镜像,再尝试从私有仓库中下载这个镜像。
docker image rm 127.0.0.1:5000/session-web:latest
docker pull 127.0.0.1:5000/session-web:latest
注意:
- 如果你不想使用127.0.0.1:5000作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 192.168.3.100:5000这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。
- 这时因为Docker默认不允许非HTTPS方式推送镜像。我们可以通过Docker的配置选项来取消这个限制。
- 对于使用systemd的系统,请在/etc/docker/daemon.json中写入如下内容(如果文件不存在请新建该文件)
{
"registry-mirrors":[
"https://registry.docker-cn.com"
],
"insecure-registries":[
"192.168.3.100:5000"
]
}