带你从零了解Docker

2013年发布至今, Docker是近年来非常火的技术, 一直广受瞩目,被认为可能会改变软件行业。而且Docker不仅仅是Linux Redhat和Canonical等Linux巨头眼里的宠儿,微软等专有软件公司也在热烈拥抱 Docker,所以就知道Docker为啥这么火了。

我相信有很多人对Docker感兴趣,都想学学Docker,毕竟天天听、毕竟这么火、毕竟技多不压身。许多人并不清楚Docker到底是什么,要解决什么问题,好处又在哪里?接下来我就详细解释一下,帮助大家理解它,还带有简单易懂的实例,教你如何将它用于日常开发。

什么是容器

一句话概括容器:容器就是将软件打包成标准化单元,以用于开发、交付和部署。

  • 容器镜像是轻量的,可执行的独立软件包,包含软件运行所需的所有内容:代码,运行时环境,系统工具,系统库和设置。
  • 容器化软件适用于基于Linux和Windows的应用,在任何环境中都能够始终如一地运行。
  • 容器赋予了软件独立性,使其免受外在环境差异(例如,开发和预演环境的差异)的影响,从而有助于减少团队间在相同基础设施上运行不同软件时的冲突。
  • 我觉得容器就是一个存放东西的地方,就像房子可以装各种家具,书架可以放各种书。我们现在所说的容器存放的东西可能更偏向于应用,比如 站,程序甚至是系统环境。

    虚拟机和容器

    虚拟机

    虚拟机就是带环境安装的一种解决方案,他可以在一种操作系统里面运行另一种操作系统,比如在Windows系统里面运行Linux系统,应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。

    虽然用户可以通过虚拟机还原软件的原始环境。但是如下缺点:

    资源占用多

    虚拟机会独占一部分内存和硬盘空间。他运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有1MB,虚拟机却需要几百MB的内存才能运行。一个系统一般只支持几十个虚拟机。

    冗余步骤多

    虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登陆。

    启动慢

    启动系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。

    Linux容器

    由于虚拟机存在这些缺点,Linux发展出了另一种虚拟化技术,Linux容器。

    Linux容器不是模拟一个完整的操作系统,而是对程序进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。

    由于容器是进程级别的,相比虚拟机有很多优势:

    启动快

    容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。

    资源占用少

    容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。一个单机上支持上千个容器。

    体积小

    容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。

    两者对比

    传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程,容器虚拟化的是操作系统而不是硬件,容器之间是共享同一套操作系统资源的。虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统。因此容器的隔离级别会稍低一些。

    简单来说,容器和虚拟机具有相似的资源隔离和分配优势,但功能有所不同,因为容器虚拟化的是操作系统,而不是硬件,因此容器更容易移植,效率也更高。而容器的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更轻便。

    容器是一个应用层抽象,用于将代码和依赖资源打包在一起。多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行。与虚拟机相比,容器占用的空间较少,瞬间就能完成启动。

    虚拟机是一个物理硬件层抽象,用于将一台服务器变成多台服务器。管理程序允许多个VM在一台机器上运行。每个VM都包含一整套操作系统,一个或多个应用,必要的二进制文件和库资源,因此占用大量空间。而VM启动也非常缓慢。

    什么是Docker

    Docker是属于Linux容器的一种封装,提供简单易用的容器使用接口,他是目前最流行的Linux容器解决方案。

    Docker将应用程序与该程序的依赖,打包在一个文件里。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了Docker,就不用担心环境问题。

    总体来说,Docker的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。

    Docker基本概念

    Docker中有三个核心概念:Image、Container、Repository。

  • 镜像(Image)
  • 容器(Container)
  • 仓库(Repository)
  • 理解了这三个概念,就理解了Docker的整个生命周期。

    镜像(Image):一个特殊的文件系统

    操作系统分为内核和用户空间。对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。而Docker镜像(Image),就相当于一个root文件系统。

    Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

    镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

    分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。

    和Windows的那种IOS镜像相比,Docker中的镜像的概念不会陌生。但是和Windows的那种IOS镜像相比,Docker中的镜像是分层的,可复用的,而非简单的一堆文件叠在一起(类似于一个压缩包的源码和一个Git仓库的区别)。

    容器(Container):镜像运行时的实体

    镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

    容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。前面讲过镜像使用的是分层存储,容器也是如此。

    容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

    容器的存在离不开镜像的支持,他是镜像运行时的一个载体(类似于实例和类的关系)。依托Docker的虚拟化技术,给容器创建了独立的端口,进程,文件等空间,Container就是一个宿机隔离“容器”。容器可宿主机之间可以进行port,volumes,network等通信。

    仓库(Repository):集中存放镜像文件的地方

    镜像构建完成后,可以很容易地在当前宿主上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。

    一个Docker Registry中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。所以说:镜像仓库是Docker用来集中存放镜像文件的地方,类似于我们之前常用的代码仓库。

    通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以latest作为默认标签。

    Docker的仓库和Git的仓库比较相似,拥有仓库名、tag。在本地构建完镜像之后,即可通过仓库进行镜像的分发。常用的Docker hub有https://hub.docker.com/ 、 https://cr.console.aliyun.com/等。

    Docker作用

    多环境的部署切换

    业务开发中往往需要区分开发环境与线上环境,利用Docker能原封不动的将开发环境中的代码与环境原封不动无污染的迁移到线上环境,配合一定的自动化流程即可实现自动的发布。

    复杂环境一键配置

    某些场景下可能会配一些超级复杂的环境,这个时候可以对Docker环境配置做封装,直接生成镜像,让大家低成本使用。

    持续集成单元测试

    类似于Travis CI这种。

    同应用多版本隔离,文件隔离

    比如这个项目依赖Java 7 ,那个项目依赖Java 8,同一个服务器上跑了100个程序,可以用Docker建立隔离开,防止互相传染。

    云构建

    同一个仓库下不同人开发往往会遇到不同的人使用不同的包版本,且自己根本不知道与别人不一样,最终导致发布之后产生线上问题。利用Docker可以在云端新建容器,远程无污染、低成本构建代码,实现不同人用的一定是同一个版本。

    省钱

    低成本安全超售。

    相关命令

    安装

    Docker的安装是非常便捷的,在macOS、Ubuntu等下面都有一键式安装工具或者脚本。更多可以参考Docker官方教程[1]。

    下面简单介绍一下Ubuntu下的安装。

    Docker支持以下的Ubuntu版本:

  • Ubuntu Precise 12.04 (LTS)
  • Ubuntu Trusty 14.04 (LTS)
  • Ubuntu Wily 15.10
  • Docker要求Ubuntu系统的内核版本高于3.10,查看本页面的前提条件来验证你的Ubuntu版本是否支持Docker。

    通过uname -r命令查看你当前的内核版本:

    1. runoob@runoob:~$ uname -r

    1、选择国内的云服务商,这里选择阿里云为例:

    1. curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh –

    2、安装所需要的包:

    1. sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual

    3、添加使用HTTPS传输的软件包以及CA证书:

    1. sudo apt-get update
    2. sudo apt-get install apt-transport-https ca-certificates

    4、添加GPG密钥:

    1. sudo apt-key adv –keyserver hkp://p80.pool.sks-keyservers.net:80 –recv-keys 58118E89F3A912897C070ADBF76221572C52609D

    5、添加软件源:

    1. echo “deb https://apt.dockerproject.org/repo ubuntu-xenial main” | sudo tee /etc/apt/sources.list.d/docker.list

    6、添加成功后更新软件包缓存:

    1. sudo apt-get update

    7、安装Docker:

    1. sudo apt-get install docker-engine

    8、启动Docker

    1. sudo systemctl enable docker
    2. sudo systemctl start docker

    寻找基础镜像

    DockerHub等 站都提供了众多镜像,一般情况下我们都会从它那找个镜像作为基础镜像,然后再进行我们的后续操作。

    拉取基础镜像

    当我们在本地主机上使用一个不存在的镜像时,Docker就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用docker pull命令来下载它。

    利用docker pull命令即可从相关Hub 站上拉取镜像到本地。同时在拉的过程中就能看到是按照多个 “层” 去拉镜像的:

    1. Crunoob@runoob:~$ docker pull ubuntu:13.10
    2. 13.10: Pulling from library/ubuntu
    3. 6599cadaf950: Pull complete
    4. 23eda618d451: Pull complete
    5. f0be3084efe9: Pull complete
    6. 52de432f084b: Pull complete
    7. a3ed95caeb02: Pull complete
    8. Digest: sha256:15b79a6654811c8d992ebacdfbd5152fcf3d165e374e264076aa435214a947a3
    9. Status: Downloaded newer image for ubuntu:13.10

    我们可以使用docker images来列出本地主机上的镜像。

    1. runoob@runoob:~$ docker images
    2. REPOSITORY TAG IMAGE ID CREATED SIZE
    3. ubuntu 14.04 90d5884b1ee0 5 days ago 188 MB
    4. php 5.6 f40e9e0f10c8 9 days ago 444.8 MB
    5. nginx latest 6f8d099c3adc 12 days ago 182.7 MB
    6. mysql 5.6 f2e8d6c772c0 3 weeks ago 324.6 MB
    7. httpd latest 02ef73cf1bc0 3 weeks ago 194.4 MB
    8. ubuntu 15.10 4e3b13c8a266 4 weeks ago 136.3 MB
    9. hello-world latest 690ed74de00f 6 months ago 960 B
    10. training/webapp latest 6fae60ef3446 11 months ago 348.8 MB

    各个选项说明:

  • REPOSITORY:表示镜像的仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小
  • 创建Docker容器

    docker create命令通过镜像去创建一个容器,同时吐出容器ID:

    1. > docker create –name ubuntuContainer ubuntu:18.04
    2. 0da83bc6515ea1df100c32cccaddc070199b72263663437b8fe424aadccf4778

    用docker start即可运行该容器:

    1. > docker start ubuntuContainer

    用docker ps即可查看运行中的container:

    1. > docker ps
    2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    3. 9298a27262da ubuntu:18.04 “/bin/bash” 4 minutes ago Up About a minute ubuntuContainer

    用docker exec即可进入该container:

    1. > docker exec -it 9298
    2. root@9298a27262da:/# ls
    3. bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
    4. root@9298a27262da:/# exit

    用docker run可以一步到位创建并运行一个容器,然后进入该容器:

    1. > docker run -it –name runUbuntuContainer ubuntu:18.04 /bin/bash
    2. root@57cdd61d4383:/# ls
    3. bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
    4. root@57cdd61d4383:/#
    5. # docker ps 可以查到已经成功运行了 runUbuntuContainer
    6. > docker ps
    7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    8. 57cdd61d4383 ubuntu:18.04 “/bin/bash” 9 seconds ago Up 8 seconds runUbuntuContainer
    9. 9298a27262da ubuntu:18.04 “/bin/bash” 9 minutes ago Up 6 minutes

    commit容器,创建新镜像

    和Ghost装Windows一样,很多时候,我们期望能定制自己的镜像,在里面安装一些基础环境(比如上文中的Node),然后制作出自己要的基础镜像。这个时候docker commit就派上用场了。

    1. > docker commit –author “rccoder” –message “curl+node” 9298 rccoder/myworkspace:v1
    2. sha256:68e83119eefa0bfdc8e523ab4d16c8cf76770dbb08bad1e32af1c872735e6f71
    3. # 通过 docker images 就能看到新制作的 rccoder/myworkspace 就躺在这里了
    4. >docker images
    5. REPOSITORY TAG IMAGE ID CREATED SIZE
    6. rccoder/myworkspace v1 e0d73563fae8 20 seconds ago 196MB

    接着,试一下我们新创建的镜像:

    1. > docker run -it –name newWorkSpace rccoder/myworkspace:v1 /bin/bash
    2. root@9109f6985735:/# node -v
    3. 8.0.0

    看起来没问题。

    push镜像到docker hub

    镜像制作好了,怎么共享出去让别人使用呢?这里以push到docker hub为例。

    第一步是先去docker hub注册一个账 ,然后在终端上登录账 ,进行 push:

    1. > docker login
    2. > docker push rccoder/myworkspace:v1
    3. The push refers to repository [docker.io/rccoder/myworkspace]
    4. c0913fec0e19: Pushing [=> ] 2.783MB/116.7MB
    5. bb1eed35aacf: Mounted from library/ubuntu
    6. 5fc1dce434ba: Mounted from library/ubuntu
    7. c4f90a44515b: Mounted from library/ubuntu
    8. a792400561d8: Mounted from library/ubuntu
    9. 6a4e481d02df: Waiting

    Dockerfile

    用Docker进行持续集成?相比在了解Docker之前肯定听过这个事情,那就意味着需要从某个地方拷贝代码,然后执行(对,听上去有点Travis CI的那种感觉)。

    是时候该Dockerfile出场了!

    Dockerfile是一个由一堆命令+参数构成的脚本,使用docker build即可执行脚本构建镜像,自动的去做一些事(同类似于Travis CI中的.travis.yml)。

    Dockerfile的格式统统为:

    1. # Comment
    2. INSTRUCTION arguments

    必须以FROM BASE_IMAGE开头指定基础镜像。

    更详细的规范与说明请参考Dockerfile reference[2]。这里我们以基于上面的rccoder/myworkspace:v1作为基础镜像,然后在根目录创建a目录为例。

    Dockerfile如下:

    1. FROM rccoder/myworkspace:v1
    2. RUN mkdir a

    然后执行:

    1. > docker build -t newfiledocker:v1 .
    2. Sending build context to Docker daemon 3.584kB
    3. Step 1/2 : FROM rccoder/myworkspace:v1
    4. —> 68e83119eefa
    5. Step 2/2 : RUN mkdir a
    6. —> Running in 1127aff5fbd3
    7. Removing intermediate container 1127aff5fbd3
    8. —> 25a8a5418af0
    9. Successfully built 25a8a5418af0
    10. Successfully tagged newfiledocker:v1
    11. # 新建基于 newfiledocker 的容器并在终端中打开,发现里面已经有 a 文件夹了。
    12. > docker docker run -it newfiledocker:v1 /bin/bash
    13. root@e3bd8ca19ffc:/# ls
    14. a bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

    借助Dockerfile的能力,Docker留下了无限的可能。

    在容器里安装MySQL

    环境方法一、docker pull php

    查找Docker Hub上的PHP镜像:

    1. runoob@runoob:~/php-fpm$ docker search php
    2. NAME DEION STARS OFFICIAL AUTOMATED
    3. php While designed for web development, the PH… 1232 [OK]
    4. richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable … 207 [OK]
    5. phpmyadmin/phpmyadmin A web interface for MySQL and MariaDB. 123 [OK]
    6. eboraas/apache-php PHP5 on Apache (with SSL support), built o… 69 [OK]
    7. php-zendserver Zend Server – the integrated PHP applicati… 69 [OK]
    8. million12/nginx-php Nginx + PHP-FPM 5.5, 5.6, 7.0 (NG), CentOS… 67 [OK]
    9. webdevops/php-nginx Nginx with PHP-FPM 39 [OK]
    10. webdevops/php-apache Apache with PHP-FPM (based on webdevops/php) 14 [OK]
    11. phpunit/phpunit PHPUnit is a programmer-oriented testing f… 14 [OK]
    12. tetraweb/php PHP 5.3, 5.4, 5.5, 5.6, 7.0 for CI and run… 12 [OK]
    13. webdevops/php PHP (FPM and CLI) service container 10 [OK]

    这里我们拉取官方的镜像,标签为5.6-fpm:

    1. runoob@runoob:~/php-fpm$ docker pull php:5.6-fpm

    等待下载完成后,我们就可以在本地镜像列表里查到REPOSITORY为PHP,标签为5.6-fpm的镜像:

    1. runoob@runoob:~/php-fpm$ docker images
    2. REPOSITORY TAG IMAGE ID CREATED SIZE
    3. php 5.6-fpm 025041cd3aa5 6 days ago 456.3 MB

    方法二、通过Dockerfile构建

    创建Dockerfile。

    首先,创建目录php-fpm,用于存放后面的相关东西:

    1. runoob@runoob:~$ mkdir -p ~/php-fpm/logs ~/php-fpm/conf

    logs目录将映射为php-fpm容器的日志目录。

    conf目录里的配置文件将映射为php-fpm容器的配置文件。

    进入创建的php-fpm目录,创建Dockerfile。

    通过Dockerfile创建一个镜像,替换成你自己的名字:

    1. runoob@runoob:~/php-fpm$ docker build -t php:5.6-fpm .

    创建完成后,我们可以在本地的镜像列表里查找到刚刚创建的镜像:

    1. runoob@runoob:~/php-fpm$ docker images
    2. REPOSITORY TAG IMAGE ID CREATED SIZE
    3. php 5.6-fpm 025041cd3aa5 6 days ago 456.3 MB
    1. https://docs.docker.com/docker-for-mac/install/#install-and-run-docker-for-mac
    2. https://docs.docker.com/engine/reference/builder/#environment-replacement

    原文链接:https://juejin.im/post/5bffdb645188251b8a270058

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2019年1月2日
    下一篇 2019年1月2日

    相关推荐