2013年发布至今, Docker 是近年来很是火的容器技术, 一直广受瞩目,被认为可能会改变软件行业。并且啊 Docker不只仅是linux Redhat 和Canonical等Linux巨头眼里的宠儿,微软等专有软件公司也在热烈拥抱 Docker,因此就知道 Docker 为啥这么火了。php
我相信有不少人对 Docker 感兴趣,都想学学 Docker,毕竟每天听、毕竟这么火、毕竟技多不压身。许多人并不清楚 Docker 究竟是什么,要解决什么问题,好处又在哪里?接下来我就详细解释一下,帮助你们理解它,还带有简单易懂的实例,教你如何将它用于平常开发。java
一句话归纳容器:容器就是将软件打包成标准化单元,以用于开发、交付和部署。node
我以为容器就是一个存放东西的地方,就像房子能够装各类家具,暑假能够放各类书。咱们如今所说的容器存放的东西可能更偏向于应用好比网站,程序甚至是系统环境。mysql
虚拟机就是带环境安装的一种解决方案,他能够再一种操做系统里面运行另外一种操做系统,好比在Windows系统里面运行Linux系统,应用程序对此毫无感知,由于虚拟机看上去跟真是系统如出一辙,而对于底层系统来讲,虚拟机就是一个普通文件,不须要了就删掉,对其余部分毫无影响。linux
虽然用户能够经过虚拟机还原团建的原始环境。可是以下缺点。nginx
(1)资源占用多git
虚拟机会独占一部份内存和硬盘空间。他运行的时候,其余程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有1MB,虚拟机却须要几百MB的内存才能运行。一个系统通常只支持几十个虚拟机。web
(2)冗余步骤多sql
虚拟机是完整的操做系统,一些系统级别的操做步骤,每每没法跳过,好比用户登录。docker
(3)启动慢
启动系统须要多久,启动虚拟机就须要多久。可能要等几分钟,应用程序才能真正运行。
因为虚拟机存在这些缺点,Linux发展出了另外一种虚拟化技术,Linux容器。
Linux容器不是模拟一个完整的操做系统,而是对程序进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来讲,它接触到的各类资源都是虚拟的,从而实现与底层系统的隔离。
因为容器是进程级别的,相比虚拟机有不少优点。
(1)启动快
容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。因此,启动容器至关于启动本机的一个进程,而不是启动一个操做系统,速度就快不少。
(2)资源占用少
容器只占用须要的资源,不占用那些没有用到的资源;虚拟机因为是完整的操做系统,不可避免要占用全部资源。另外,多个容器能够共享资源,虚拟机都是独享资源。一个单机上支持上千个容器。
(3)体积小
容器只要包含用到的组件便可,而虚拟机是整个操做系统的打包,因此容器文件比虚拟机文件要小不少。
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操做系统,在该系统上再运行所需应用进程,容器虚拟化的是操做系统而不是硬件,容器之间是共享同一套操做系统资源的。虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操做系统。所以容器的隔离级别会稍低一些。
简单来讲,容器和虚拟机具备类似的资源隔离和分配优点,但功能有所不一样,由于容器虚拟化的是操做系统,而不是硬件,所以容器更容易移植,效率也更高。而容器的应用进程直接运行于宿主的内核,容器内没有本身的内核,并且也没有进行硬件虚拟。所以容器要比传统虚拟机更轻便。
容器是一个应用层抽象,用于将代码和依赖资源打包在一块儿。多个容器能够在同一台机器上运行,共享操做系统内核,但各自做为独立的进程在用户空间中运行。与虚拟机相比,容器占用的空间交少,瞬间就能完成启动。
虚拟机是一个物理硬件层抽象,用于将一台服务器变成多台服务器。管理程序容许多个vm在一台机器上运行。每一个vm都包含一整套操做系统,一个或多个应用,必要的二进制文件和库资源,所以占用大量空间。而vm启动也很是缓慢。
Docker是属于Linux容器的一种封装,提供简单易用的容器使用接口,他是目前最流行的Linux容器解决方案。
Docker 将应用程序与该程序的依赖,打包在一个文件里。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行同样。有了Docker,就不用担忧环境问题。
整体来讲,Docker 的接口至关简单,用户能够方便地建立和使用容器,把本身的应用放入容器。容器还能够进行版本管理、复制、分享、修改,就像管理普通的代码同样。
理解了这三个概念,就理解了 Docker 的整个生命周期,
操做系统分为内核和用户空间。对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。而Docker镜像(Image),就至关于一个root文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建以后也不会被改变。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在本身这一层。好比,删除前一层文件的操做,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,可是实际上该文件会一直跟随镜像。所以,在构建镜像的时候,须要额外当心,每一层尽可能只包含该层须要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至能够用以前构建好的镜像做为基础层,而后进一步添加新的层,以定制本身所需的内容,构建新的镜像。
和windows的那种iso镜像相比,Docker中的镜像的概念不会陌生。可是windows的那种iso镜像相比,Docker中的镜像是分层的,可复用的,而非简单的一堆文件碟在一块儿(相似于一个压缩包的源码和一个git仓库的区别)
容器的实质是进程,但与直接在宿主执行的进程不一样,容器进程运行于属于本身的独立的 命名空间。前面讲过镜像使用的是分层存储,容器也是如此。
容器存储层的生存周期和容器同样,容器消亡时,容器存储层也随之消亡。所以,任何保存于容器存储层的信息都会随容器删除而丢失。
容器的存在离不开镜像的支持,他是镜像运行时的一个载体(相似于实例和类的关系)。依托Docker的虚拟化技术,给容器建立了独立的端口,进程,文件等空间,Container就是一个宿机隔离“容器”。容器可宿主机之间能够进行port,volumes,network等通讯。
镜像构建完成后,能够很容易的在当前宿主上运行,可是, 若是须要在其它服务器上使用这个镜像,咱们就须要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。
一个 Docker Registry中能够包含多个仓库(Repository);每一个仓库能够包含多个标签(Tag);每一个标签对应一个镜像。因此说:镜像仓库是Docker用来集中存放镜像文件的地方相似于咱们以前经常使用的代码仓库。
一般,一个仓库会包含同一个软件不一样版本的镜像,而标签就经常使用于对应该软件的各个版本 。咱们能够经过<仓库名>:<标签>
的格式来指定具体是这个软件哪一个版本的镜像。若是不给出标签,将以 latest 做为默认标签.。
业务中王湾须要区分开发环境与线上环境,利用Docker能原封不动的将开发环境中的代码与环境原封不动无污染的迁移到线上环境,配合必定的自动胡流程便可自哦对那个发动。
某些场景下可能会配一些超级复杂的环境,这个时候能够对Docker对环境配置作封装,直接生成镜像,让你们低成本使用。
相似于 travis-ci 这种
好比这个项目依赖java 7 ,那个项目依赖java 8,同一个服务器上跑了100个陈永,能够用Docker创建隔离开,防止互相传染。
同一个仓库下不一样人开发每每会遇到不一样的人使用不一样的 包版本且本身根本不知道与别人不同,最终致使发布以后产生线上问题。利用 Docker 能够在云端新建容器,远程 无污染、低成本 构建代码,实现 不一样人用的必定是同一个版本。
低成本安全超售
Docker 的安装是很是便捷的,在 macOS、ubuntu 等下面都有一键式安装工具或者脚本。更多能够参考 Docker 官方教程。
下面简单介绍一下ubuntu下的安装。
Docker 支持如下的 Ubuntu 版本:
经过 uname -r 命令查看你当前的内核版本
runoob@runoob:~$ uname -r
1.选择国内的云服务商,这里选择阿里云为例
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -复制代码
2.安装所须要的包
sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual复制代码
3.添加使用 HTTPS 传输的软件包以及 CA 证书
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates复制代码
4.添加GPG密钥
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D复制代码
5.添加软件源
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list复制代码
6.添加成功后更新软件包缓存
sudo apt-get update复制代码
7.安装docker
sudo apt-get install docker-engine复制代码
8.启动 docker
sudo systemctl enable docker
sudo systemctl start docker复制代码
DockerHub 等网站都提供了众多镜像,通常状况下咱们都会从它那找个镜像做为基础镜像,而后再进行咱们的后续操做。
当咱们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。若是咱们想预先下载这个镜像,咱们可使用 docker pull 命令来下载它。
利用docker pull 命令便可从相关 hub 网站上拉取镜像到本地。同时在拉的过程当中就能看到是按照多个 “层” 去拉镜像的
Crunoob@runoob:~$ docker pull ubuntu:13.10
13.10: Pulling from library/ubuntu
6599cadaf950: Pull complete
23eda618d451: Pull complete
f0be3084efe9: Pull complete
52de432f084b: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:15b79a6654811c8d992ebacdfbd5152fcf3d165e374e264076aa435214a947a3
Status: Downloaded newer image for ubuntu:13.10复制代码
咱们可使用 docker images 来列出本地主机上的镜像。
runoob@runoob:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 90d5884b1ee0 5 days ago 188 MB
php 5.6 f40e9e0f10c8 9 days ago 444.8 MB
nginx latest 6f8d099c3adc 12 days ago 182.7 MB
mysql 5.6 f2e8d6c772c0 3 weeks ago 324.6 MB
httpd latest 02ef73cf1bc0 3 weeks ago 194.4 MB
ubuntu 15.10 4e3b13c8a266 4 weeks ago 136.3 MB
hello-world latest 690ed74de00f 6 months ago 960 B
training/webapp latest 6fae60ef3446 11 months ago 348.8 MB复制代码
各个选项说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像建立时间
SIZE:镜像大小
docker create 命令经过镜像去建立一个容器,同时吐出容器 id。
> docker create --name ubuntuContainer ubuntu:18.04
0da83bc6515ea1df100c32cccaddc070199b72263663437b8fe424aadccf4778
复制代码复制代码
用 docker start 便可运行改容器。
> docker start ubuntuContainer
复制代码复制代码
用 docker ps 便可查看运行中的 container
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9298a27262da ubuntu:18.04 "/bin/bash" 4 minutes ago Up About a minute ubuntuContainer
复制代码复制代码
用 docker exec 便可进入该 container。
> docker exec -it 9298
root@9298a27262da:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@9298a27262da:/# exit
复制代码复制代码
用 docker run 能够一步到位建立并运行一个容器,而后进入该容器。
> docker run -it --name runUbuntuContainer ubuntu:18.04 /bin/bash
root@57cdd61d4383:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@57cdd61d4383:/#
# docker ps 能够查到已经成功运行了 runUbuntuContainer
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57cdd61d4383 ubuntu:18.04 "/bin/bash" 9 seconds ago Up 8 seconds runUbuntuContainer
9298a27262da ubuntu:18.04 "/bin/bash" 9 minutes ago Up 6 minutes 复制代码
和 Ghost 装 windows 同样,不少时候,咱们指望能定制本身的镜像,在里面安装一些基础环境(好比上文中的 node),而后制做出本身要的基础镜像。这个时候 docker commit 就派上用场了。
> docker commit --author "rccoder" --message "curl+node" 9298 rccoder/myworkspace:v1
sha256:68e83119eefa0bfdc8e523ab4d16c8cf76770dbb08bad1e32af1c872735e6f71
# 经过 docker images 就能看到新制做的 rccoder/myworkspace 就躺在这里了
>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rccoder/myworkspace v1 e0d73563fae8 20 seconds ago 196MB
复制代码复制代码
接着,试一下咱们新建立的镜像?
> docker run -it --name newWorkSpace rccoder/myworkspace:v1 /bin/bash
root@9109f6985735:/# node -v
8.0.0
复制代码复制代码
看起来没问题。
镜像制做好了,怎么共享出去让别人使用呢?这里以 push 到 docker hub 为例。
第一步是先去 docker hub 注册一个帐号,而后在终端上登陆帐号,进行 push。
> docker login
> docker push rccoder/myworkspace:v1
The push refers to repository [docker.io/rccoder/myworkspace]
c0913fec0e19: Pushing [=> ] 2.783MB/116.7MB
bb1eed35aacf: Mounted from library/ubuntu
5fc1dce434ba: Mounted from library/ubuntu
c4f90a44515b: Mounted from library/ubuntu
a792400561d8: Mounted from library/ubuntu
6a4e481d02df: Waiting复制代码
用 Docker 进行持续集成?相比在了解 Docker 以前确定听过这个事情,那就意外着须要从某个地方拷贝代码,而后执行(对,听上去有点 travis-ci 的那种感受)。
是时候该 Dockerfile 出场了!
Dockerfile 是一个由一堆命令+参数构成的脚本,使用 docker build 便可执行脚本构建镜像,自动的去作一些事(同相似于travis-ci 中的 .travis.yml
)。
Dockerfile 的格式通通为:
# Comment
INSTRUCTION arguments
复制代码复制代码
必须以 FROM BASE_IMAGE
开头指定基础镜像。
更详细的规范与说明请参考 Dockerfile reference。这里咱们以基于上面的 rccoder/myworkspace:v1 做为基础镜像,而后在根目录建立 a 目录为例
Dockerfile 以下:
FROM rccoder/myworkspace:v1
RUN mkdir a
复制代码复制代码
而后执行:
> docker build -t newfiledocker:v1 .
Sending build context to Docker daemon 3.584kB
Step 1/2 : FROM rccoder/myworkspace:v1
---> 68e83119eefa
Step 2/2 : RUN mkdir a
---> Running in 1127aff5fbd3
Removing intermediate container 1127aff5fbd3
---> 25a8a5418af0
Successfully built 25a8a5418af0
Successfully tagged newfiledocker:v1
# 新建基于 newfiledocker 的容器并在终端中打开,发现里面已经有 a 文件夹了。
> docker docker run -it newfiledocker:v1 /bin/bash
root@e3bd8ca19ffc:/# ls
a bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
复制代码复制代码
借助 Dockerfile 的能力,Docker 留下了无限的可能。
查找Docker Hub上的php镜像
runoob@runoob:~/php-fpm$ docker search php
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
php While designed for web development, the PH... 1232 [OK]
richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable ... 207 [OK]
phpmyadmin/phpmyadmin A web interface for MySQL and MariaDB. 123 [OK]
eboraas/apache-php PHP5 on Apache (with SSL support), built o... 69 [OK]
php-zendserver Zend Server - the integrated PHP applicati... 69 [OK]
million12/nginx-php Nginx + PHP-FPM 5.5, 5.6, 7.0 (NG), CentOS... 67 [OK]
webdevops/php-nginx Nginx with PHP-FPM 39 [OK]
webdevops/php-apache Apache with PHP-FPM (based on webdevops/php) 14 [OK]
phpunit/phpunit PHPUnit is a programmer-oriented testing f... 14 [OK]
tetraweb/php PHP 5.3, 5.4, 5.5, 5.6, 7.0 for CI and run... 12 [OK]
webdevops/php PHP (FPM and CLI) service container 10 [OK]
...复制代码
这里咱们拉取官方的镜像,标签为5.6-fpm
runoob@runoob:~/php-fpm$ docker pull php:5.6-fpm复制代码
等待下载完成后,咱们就能够在本地镜像列表里查到REPOSITORY为php,标签为5.6-fpm的镜像。
runoob@runoob:~/php-fpm$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php 5.6-fpm 025041cd3aa5 6 days ago 456.3 MB复制代码
建立Dockerfile
首先,建立目录php-fpm,用于存放后面的相关东西。
runoob@runoob:~$ mkdir -p ~/php-fpm/logs ~/php-fpm/conf复制代码
logs目录将映射为php-fpm容器的日志目录
conf目录里的配置文件将映射为php-fpm容器的配置文件
进入建立的php-fpm目录,建立Dockerfile
经过Dockerfile建立一个镜像,替换成你本身的名字
runoob@runoob:~/php-fpm$ docker build -t php:5.6-fpm .复制代码
建立完成后,咱们能够在本地的镜像列表里查找到刚刚建立的镜像
runoob@runoob:~/php-fpm$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
php 5.6-fpm 025041cd3aa5 6 days ago 456.3 MB复制代码