1. Docker

注解

更新日期:2020-03-23

1.1. 书籍推荐

1.2. 初识Docker

注解

总的来说,Docker属于运维部署领域。如果是应用者就是熟练的在合适的场景下操作相应的命令;如果是进一步研究其底层原理,那需要的基础就要多些了,比如虚拟化技术。

  1. Docker就是开源的容器引擎,诞生于2013年。最形象的比喻就是集装箱,各自自成体系,互不影响,可任意放在不同的平台。
  2. Docker是容器的一种,容器是一种*轻量级(占用空间小)的虚拟技术*,相对应的,虚拟机(VMware、VirtualBox等)就是重量级的虚拟技术。
  3. Docker是虚拟化的是操作系统,而虚拟机虚拟化的是硬件。
  4. 最切实的价值是什么?
    • 项目开发有三大基础环境: 开发环境(程序员)、测试环境(测试人员)、生产环境(运维人员)。
    • 要保持三者环境的统一Docker的优势不明觉厉。举个例子,小王,程序员一枚,在自己电脑上优雅的完成了业务开发。怀着如释重负的心情将代码推送至测试环境,然后休息,进行吃鸡游戏……。突然,测试人员小李发来消息,小王呀,你昨天推的代码不work呀,小王说:不可能!我本地非常work的,你再仔细看看吧……;小李说:我这真没问题。
    • 你看看是不是吃鸡的心情不好了!问题究竟在哪里呢?原来呀小王本地开发环境使用的Python3.7,但是小李所用的测试环境是Python3.6,造成了有些功能不work。如果我们有了Docker,就可以代码+环境保持一致,不再造成上面的尴尬!
  5. 可移植。MAC、Win、Linux等平台。
  6. 相互隔离。
  7. 开销低。

Docker是一种容器技术,解决软件跨环境迁移的问题!

1.3. 图述Docker

../../_images/overview.png

1.4. Docker架构(组件)

重要

Docker采用C/S架构。Docker客户端(Client)可以通过命令行形式或API来与提供Docker服务(Server)的守护进程进行通信。

1.4.1. 基本架构图

../../_images/2020-03-06-docker架构.png

1.4.2. 核心组件

重要

Docker共包含三大核心组件:镜像(image)、容器(container)、仓库(Repository)。镜像和容器可以类比面向对象编程中类和实例的关系,image->class、container->instance。仓库可类别代码控制中心,负责存储和共享用户的镜像。

  1. Image
    • 一个只读的静态模板。存储容器所需要的环境和应用的执行代码。相当于是一个root文件系统,比如官方镜像Python:3.9就包含了完整的一套Python3.9最小系统的root文件系统。
    • 采用分层机制。
  2. Container
    • 一个运行时的环境。镜像是静态的定义,容器是镜像运行时的实体。
    • 容器就相当于集装箱,不关心里面装什么,所有应用都有统一的生命周期:创建、启动、删除、暂停、重启等。
    • 容器也不在乎自己所处的平台。本机、虚拟机、服务器等都可相互移植,对于前面提到的部署都是非常适合的。
  3. Repository
    • Docker采用注册服务器来存储和共享用户的镜像。
    • 注册服务器分为公共和私有两种。公共就是官方的Docker Hub,私有就是自己注册一个Docker Hub账号建立自己的私有仓库,便于小范围内的共享。

1.4.3. 通过Docker开发和部署的流程图

注解

利用下图能更好的理解Docker在日常开发、部署中的应用流程和三大组件。

../../_images/docker-开发部署流程图.png
流程概述:
  • 开发主机上
    1. 创建容器A,创建方法可以手动也可通过Dockerfile文件自动构建。

    小技巧

    Dockerfile文件后续会讲,这也是最常用的一种构建容器方式。

    1. 容器A必须基于镜像来创建。镜像A就是容器的静态形式,容器是镜像的动态形式。
    2. 将容器A保存为镜像A,然后推送到Docker库进行共享
  • 集群环境上
    1. 在Docker库中搜索所需镜像A,并将其拉取到本地。
    2. 拉取后在本地就可以运行容器A了。
    3. 在集群环境中可以运行很多容器,彼此相互独立、互不影响。

1.5. 安装Docker(MAC)并注册国内镜像加速器

小技巧

MAC系统可以直接安装桌面版Docker,社区版就够用了。关于镜像加速器推荐使用国内阿里云镜像加速器,配置也比较容易,配置后再使用docker镜像就比较快了。 官网下载太慢吗?推荐前往:http://get.daocloud.io/

1.5.1. 安装

  1. 点击 下载 docker桌面版。
  2. 查看docker版本,验证是否安装成功
$ docker -v
Docker version 19.03.5, build 633a0ea

1.5.2. 配置阿里云镜像加速器

step-1:使用阿里云或支付宝等账号登录 阿里云镜像加速器 网站。
step-2:登录后就能看到针对不同操作系统的操作步骤了。如下图所示:
../../_images/2020-03-06阿里云镜像加速器.jpg

1.6. Docker常用命令

注解

本章是docker知识的重点,基本都是命令。跟着命令敲起你的小键盘吧。

1.6.1. Docker服务(Daemon)相关命令

注解

mac系统下直接点击客户端就启动了docker服务,非常简单。使用Mac系统,就可以跳过这部分内容了。 为了使本笔记不失一般性,这里使用CentOS进行相关命令演示。

休息一下:你们公司更倾向于选择什么操作系统作为服务器呢?centos、RH、Linux? why? 知乎 上有一篇帖子讨论了这个问题。

  1. 启动docker服务
    $ systemctl start docker
    
  2. 停止docker服务
    $ systemctl stop docker
    
  3. 重启docker服务
    $ systemctl restart docker
    
  4. 查看docker服务状态
    $ systemctl status docker
    ● docker.service - Docker Application Container Engine
    Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
    Active: active (running) since  2019-12-12 10:06:56 CST; 2 months 24 days ago
    Docs: https://docs.docker.com
    
  5. 开机启动docker服务
    $ systemctl enable docker
    

1.6.2. Docker镜像(Image)相关命令

  1. 查看

    小技巧

    • docker images -q 查看所有镜像ID
    • docker iamges 查看所有镜像信息
    $ docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    python              3.8                 f88b2f81f83a        9 days ago          933MB
    nginx               latest              2073e0bcb60e        4 weeks ago         127MB
    ubuntu              14.04               6e4f1fe62ff1        2 months ago        197MB
    

    注解

    可以看到,执行命令后列出了已创建(可能你还没有镜像,列表就为空)的镜像。下面针对表头做一个说明。

    • REPOSITORY: 仓库名称
    • TAG:版本号,默认为latest
    • IMAGE ID:镜像唯一标识
    • CREATED :创建时间
    • SIZE :镜像所占的虚拟大小
  2. 搜索

    小技巧

    • docker search [name]
    $ docker search mysql
    NAME                              DESCRIPTION                                     STARS               OFFICIAL (是否官方)           AUTOMATED
    mysql                             MySQL is a widely used, open-source relation…   9196                [OK]
    mariadb                           MariaDB is a community-developed fork of MyS…   3274                [OK]
    mysql/mysql-server                Optimized MySQL Server Docker images. Create…   679                 [OK]
    centos/mysql-57-centos7           MySQL 5.7 SQL database server                   70
    
    搜索是联网进行的,列出可用的镜像。官方镜像搜索网站,可以查看下有没有自己想要的版本。
  3. 拉取(下载)

    小技巧

    • docker pull [name]:[tag]
    • 不写tag,则默认为latest
    • 访问 Docker Hub 镜像网站,可以了解更多关于的版本信息。
    $ docker pull mysql:5.6
    5.6: Pulling from library/mysql
    6d28e14ab8c8: Pull complete
    dda15103a86a: Pull complete
    55971d75ab8c: Pull complete
    f1d4ea32020b: Pull complete
    61420072af91: Pull complete
    30862a48418b: Pull complete
    c6c2ee3a9a57: Pull complete
    0f4efadb31df: Pull complete
    dd931017b211: Pull complete
    488a86083079: Pull complete
    921d4bdabca2: Pull complete
    Digest: sha256:a72a05bcf3914c902070765a506b1c8c17c06400258e7b574965763099dee9e1
    Status: Downloaded newer image for mysql:5.6
    docker.io/library/mysql:5.6
    
    上面的拉取镜像过程就体现了分层。
  4. 删除

    小技巧

    • 单个删除 docker rmi image-id/[name]:[tag]
      • rmi。rm就是删除,i参数指的就是镜像。可以指定一个或多个镜像名称或者镜像的ID,多个镜像之间可以使用空格隔开。
    • 删除本次所有镜像: docker rmi docker images -q
      • docker images -q 列出所有镜像的ID
    $ docker rmi c8078e
    Untagged: mysql:5.6
    Untagged: mysql@sha256:a72a05bcf3914c902070765a506b1c8c17c06400258e7b574965763099dee9e1
    Deleted: sha256:c8078e8ab06d8dabd6c30cffb03951fa035d85f75c19a83ace29b01cb3ecd272
    

    警告

    • 如果不能删除成功,可能是因为这个镜像正在被容器使用。
      • 可以使用 -f参数强制删除。
      • 也可以先移除正在使用该镜像的容器后再删除。

1.6.3. docker容器(container)相关命令

  1. 查看

    小技巧

    • docker ps
      • 查看正在开启的容器
    • docker ps -a
      • 查看所有创建的容器列表
    $ docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    
    $ docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                                         NAMES
    3c7e127ff4ae        nginx:v3            "/bin/bash"              29 minutes ago      Exited (0) 25 minutes ago                                                 web_server
    
  2. 创建

    小技巧

    • docker run -i -t –name=container_name image_name:tag /bin/bash
    • docker run -i -d –name=container_name image_name:tag /bin/bash
      • -i -d[t] 可以合并为-id[t]。d标志位表示创建后台容器。
    • 退出容器:执行exit命令。
      • 退出后容器将关闭
    $ docker run -it --name=web_server nginx:v3 /bin/bash
    
    root@3c7e127ff4ae:/# ls
    bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
    boot  etc  lib   media  opt  root  sbin  sys  usr
    
    $ docker run -id --name=app_server  nginx:v3  /bin/bash
    
    4b19f6042d9739a3dba3eccd93d4404259883ecf0f6402232124357914835b30
    
  3. 进入

    小技巧

    docker exec -it [容器名称] /bin/bash

    $ docker exec -it app_server /bin/bash
    root@4b19f6042d97:/#
    $ exit
    $ docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    4b19f6042d97        nginx:v3            "/bin/bash"         4 minutes ago       Up 4 minutes        80/tcp              app_server
    
  4. 启动
    • docker start [app_server]
  5. 停止
    • docker stop [app_server]
  6. 删除
    • docker rm app_server
      • 删除单个
    • docker rm `docker ps -aq`
      • 删除所有
      • q标志表示只列出容器ID,不列出其他信息。

    注解

    `符号是键盘table上方的键位

  7. 查看容器信息
    • docker inspect [app_server]

1.7. Docker容器的数据卷

小技巧

主要探讨容器中的应用数据管理相关话题。如数据如何保存、外部如何使用数据等。

1.7.1. 概念及作用

1.7.1.1. 概念

  1. 数据卷是宿主机中的一个目录或文件。
  2. 容器目录(文件)和数据卷目录(文件)绑定后,双方修改会立即同步。
  3. 一个数据卷可被多个容器挂载;一个容器也可挂载多个数据卷。

1.7.1.2. 作用

  1. 可持久化保存容器数据。
  2. 实现外部机器和容器间接通信。
  3. 容器之间进行数据交换。

1.7.2. 配置数据卷

小技巧

  1. 创建容器时,使用-v参数
    • docker run …… -v 宿主机目录(文件):容器内部目录(文件)
    • 目录不存在时,会自动创建。
    • 目录是绝对路径。
    • 可以挂载多个数据卷。
../../_images/docker数据卷.png
  1. 挂载单个数据卷:将本机的host_data目录挂载到容器的container_data下

    $ docker run -it --name=c1 -v /Users/hanghangli/Desktop/host_data:/root/container_data  nginx:v3
    # 进入容器
    $docker exec -it c1 /bin/bash
    $root@2c651df94731:/# cd root/
    # 可以看到在容器内已经有了挂载目录
    $root@2c651df94731:~# ls
    container_data
    
  2. 一个容器挂载多个数据卷:将本机的data_1.txt、data_2.txt文件挂载到容器的container_data_1.txt、container_data_2.txt

    $ docker run -it --name=c2 \
    -v /Users/hanghangli/Desktop/data_1.txt:/root/container_data_1.txt \
    -v /Users/hanghangli/Desktop/data_1.txt:/root/container_data_2.txt \
    nginx:v3
    # 进入容器
    $ docker exec -it c2 /bin/bash
    $ ls root/
    # 可以看到在容器内已经有了挂载的两个文件
    container_data_1.txt  container_data_2.txt
    $ cat container_data_1.txt
    
  3. 多个容器挂载一个数据卷。c3与c4容器挂载一个config.ini.txt文件

    $ docker run -it --name=c3 \
    -v /Users/hanghangli/Desktop/config.ini.txt:/root/container_config.ini.txt.txt \
    nginx:v3
    $ docker run -it --name=c4 \
    -v /Users/hanghangli/Desktop/config.ini.txt:/root/container_config.ini.txt \
    nginx:v3
    # 现在修改一下config.ini.txt文件内容并查看下容器的数据卷是否同步了修改。
    # 先看下c3容器
    $ docker exec -it c3 /bin/bash
    $ root@d8b63fe631cb:~# ls
        container_config.ini.txt.txt
    $ root@d8b63fe631cb:~# cat container_config.ini.txt.txt
        我修改了宿主机的配置文件。
    $ root@d8b63fe631cb:~# exit
    # 再看下c4容器
    $ docker exec -it c4 /bin/bash
    $ root@cfb85d4cb3c4:/# cat root/container_config.ini.txt
        我修改了宿主机的配置文件。
    

1.7.3. 配置 数据卷容器

小技巧

  • 使用场景:的时,并不想指定挂载的宿主机的目录,只想实现容器与容器之间的数据共享。
  • 上面的方法是给每个容器挂载本地数据卷,这样在容器比较少的情况下是一个好方法。但当我们的容器很多且都有挂载数据卷的需求,上面的方式就显得不够高效和友好。
  • 我们可以考虑专门做个挂载数据卷的容器,让它专门负责数据卷挂载,其他容器直接挂载这个数据卷容器即可。这样就增加了可扩展行和可维护性!

⚠️无论数据卷容器停止还是删除都不会影响其他容器对于数据卷的使用!

  • 容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器
../../_images/docker数据卷容器.png
  • 创建数据卷容器test_1
    1. docker run -it –name=test_1 -v /volume image:tag /bin/bash
  • 挂载数据卷test_1给容器test_2、test_3
    1. docker run -it –name=test_2 –volumes-from test_1 image:tag /bin/bash
    2. docker run -it –name=test_3 –volumes-from test_1 image:tag /bin/bash
# 创建数据卷容器 会自动分配一个目录
$ docker run -it --name=test_1 -v /volume nginx  /bin/bash

# 挂载test_1到test_2
$ docker run -it --name=test_2 --volumes-from test_1 nginx  /bin/bash
# 挂载test_1到test_3
$ docker run -it --name=test_3 --volumes-from test_1 nginx  /bin/bash

# 我们可以测试数据同步情况,我在test_1容器/volume目录新建一个config.ini,看下test_2和test_3下是否会出现呢?
$ root@75fb3393fb19:/volume# echo "hello,Docker" >> config.ini
# 在test_2下的volume目录中查看写入内容
$ docker exec -it test_2 /bin/bash
$ root@95025edc8a00:/# cat volume/config.ini
    hello,Docker
# 类似的test_3下也会出现的,自己看下吧,聪明的你看到了吗?

1.8. Docker使用案例(应用部署实战)

注解

  • 下面就进入Docker的在我们开发中的实际应用了,让我们一点点感受它带来的便利吧。加油,老铁们!
  • 如果抽象出来部署操,可分为以下几步:
    • 搜索需要安装的软件(镜像)。如mysql的版本。
    • 从仓库获取镜像。从私有或公共仓库获取。
    • 创建容器。创建容器的方式可以是命令行也可以使用Dockerfile文件来build。
    • 完成。

1.8.1. MySQL部署

  1. 目标

    实现在Docker中部署MySQL,并通过外部客户端操作该容器中的数据库。

    小技巧

    思考:外部如何访问容器内的数据库呢? 解决方案:引入端口映射方法。

  2. 过程
    • 搜索mysql (可省略步骤)

      docker search mysql:5.6

    • 拉取mysql

      docker pull mysql:5.6

    • 创建容器
      # 在本地创建一个数据库目录并进入。
      $ mkdir mysql
      $ cd ~/mysql
      # $PWD表示当前目录路径
      $ docker run -id \
      -p 3307:3306 \
      --name mysql_container \
      -v $PWD/conf:/etc/mysql/conf.d \
      -v $PWD/logs:/logs \
      -v $PWD/data:/var/lib/mysql \
      -e MYSQL_ROOT_PASSWORD=pass \
      mysql:5.6
      e39f78f46f1585225bab52499ad4d81032bc35d52972341503f47bdd1992d277
      $ docker ps
      CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
      e39f78f46f15        mysql:5.6           "docker-entrypoint.sh"   7 seconds ago       Up 5 seconds        0.0.0.0:3307->3306/tcp   mysql_container
      
      • 参数说明
        • -p 3307:3306 端口映射。将容器mysql的3306映射到主机的3307。
        • -v $PWD/conf:/etc/mysql/conf.d 挂载数据库配置数据卷。将本地(刚才创建的mysql目录)当前目录的conf挂载到容器/etc/mysql/conf.d
        • -v $PWD/logs:/logs 挂载日志数据卷。将本地当前目录的logs挂载到容器/logs。
        • -v $PWD/data:/var/lib/mysql 挂载数据数据卷。将本地当前目录的data挂载到容器/var/lib/mysql
        • -e MYSQL_ROOT_PASSWORD=pass 初始化root用户的密码
    • 操作容器中的mysql
      # 进入容器
      $ docker exec -it mysql_container /bin/bash
      # 在容器中登录mysql
      root@e39f78f46f15:/#  mysql -uroot -ppass
      mysql>
      # 下面我们可以在本地用任意客户端登录mysql,注意端口填写3307就行。登录后可以常见一个数据库和表,再进入容器就会看到刚才创建的表了。
      # 到此,mysql的容器化就完成啦。
      
      # 其他命令:mysql容器端口的映射信息
      $ docker port mysql_container 3306
          0.0.0.0:3307
      

1.8.2. Tomcat部署

  1. 目标
    • 实现在Docker中部署Tomcat,并通过本地浏览器访问网页,确定服务器是否正常工作。
  2. 创建过程
    • 拉取镜像
      # 在本地创建一个数据库目录并进入。
      $ mkdir tomcat
      $ cd tomcat
      # $PWD表示当前目录路径
      $ docker pull tomcat
      Using default tag: latest
      latest: Pulling from library/tomcat
      50e431f79093: Pull complete
      dd8c6d374ea5: Pull complete
      c85513200d84: Pull complete
      55769680e827: Pull complete
      e27ce2095ec2: Pull complete
      5943eea6cb7c: Pull complete
      3ed8ceae72a6: Pull complete
      91d1e510d72b: Pull complete
      98ce65c663bc: Pull complete
      27d4ac9d012a: Pull complete
      Digest: sha256:2c90303e910d7d5323935b6dc4f8ba59cc1ec99cf1b71fd6ca5158835cffdc9c
      Status: Downloaded newer image for tomcat:latest
      
    • 创建Tomcat容器
      # 在本地创建一个数据库目录并进入。
      $ mkdir tomcat
      $ cd tomcat
      # $PWD表示当前目录路径
      
      $ docker run -id --name=tomcat \
          -p 8080:8080 \
          -v $PWD:/usr/local/tomcat/webapps \
          tomcat
      
          5949c2cfd5fe1d4d3395996d22804d08e7e5debc8255d032fd12ab1f1d54be4f
      
    • 使用容器

1.8.3. Nginx部署

  • 拉取镜像
    $ docker pull nginx
    Using default tag: latest
    latest: Pulling from library/nginx
    68ced04f60ab: Pull complete
    28252775b295: Pull complete
    a616aa3b0bf2: Pull complete
    Digest: sha256:2539d4344dd18e1df02be842ffc435f8e1f699cfc55516e2cf2cb16b7a9aea0b
    Status: Downloaded newer image for nginx:latest
    
  • 创建容器并测试
    # 准备工作
    $ mkdir nginx
    $ cd nginx
    $ mkdir conf html logs
    $ vim conf/nginx.conf
        #user  nobody;
        worker_processes  1;
    
        #error_log  logs/error.log;
        #error_log  logs/error.log  notice;
        #error_log  logs/error.log  info;
    
        #pid        logs/nginx.pid;
    
        events {
            worker_connections  1024;
        }
    
        http {
            include       mime.types;
            default_type  application/octet-stream;
    
            #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
            # '$status $body_bytes_sent "$http_referer" '
            # '"$http_user_agent" "$http_x_forwarded_for"';
            #access_log  logs/access.log  main;
            sendfile        on;
            #tcp_nopush     on;
            #keepalive_timeout  0;
            keepalive_timeout  65;
            #gzip  on;
        include /etc/nginx/conf.d/*.conf;
        }
    $ echo '<h1>Hello, Nginx. </h1>' > html/index.html
    $ docker run -id --name=my_nginx \
        -p 80:80 \
        -v $PWD/conf/nginx.conf:/etc/nginx/nginx.conf \
        -v $PWD/logs:/var/log/nginx \
        -v $PWD/html:/usr/share/nginx/html \
        nginx
    $ 访问0.0.0.0
        Hello, Nginx.
    

1.8.4. Redis部署(一个key-value存储系统)

  • 目标
    • 创建Redis容器,并使用本地机器进行访问。
  • 拉取镜像
    • docker pull reids
  • 创建容器

    $ docker run -id --name=my_redis \
    -p 6379:6379 \
    redis
    # 内部先测试下
    $ docker exec -it my_redis /bin/bash
    $ root@679f5de7ab12:/data# redis-cli
    $ 27.0.0.1:6379> set name 'test'
        OK
    $ 127.0.0.1:6379> get name
        "test"
    
  • 外部连接测试
    • mac系统下安装Redis
      • brew install redis

      小技巧

      如果下载太慢可更换brew的仓库源,可参考:https://www.jianshu.com/p/8a2ac505ff3e

    • 连接测试

      $ redis-cli -h 0.0.0.0 -p 6379
      $ 0.0.0.0:6379> get name
          "test"
      

1.9. 使用Dockerfile制作镜像

1.9.1. 镜像原理

  • 镜像是由特殊的文件系统叠加而成。

  • 采用分层的文件系统,通过在只读文件(镜像)上增加可读写层(容器)的形式来改变镜像。

  • Docker镜像结构图
    ../../_images/Docker镜像结构.png
    • bootfs。启动文件系统镜像,复用了宿主机的文件系统。
      • 这也就解释了我们单独下载Ubuntu可能就是好几个G大小,但是利用docker就是几百兆的大小。
    • rootfs。根文件系统,也成为根镜像,一般就是一个操作系统。
    • Image-1、Image-2。这些就是我们用户的镜像,可以不断叠加,下层为父镜像。
      • 这也就解释了如果单独下载MySQL可能也就几十兆的大小,但使用docker就要几百兆的大小,反而变大了。究其原因,就是只读文件存在依赖的关系,叠加后变大了。
    • 可读写文件。这一层就是容器了,当我们基于镜像进行容器启动时,就会在最顶层加载一个可读写的文件系统作为容器。
    • 修改完后就可以提交新的镜像(制作一个新镜像)了。
  • 创建新的镜像本质上也就是对已有的镜像文件集合进行增、删、改的操作。

  • 这种叠加的方式有利于实现镜像共享、增加可扩展性、减少磁盘空间使用。

1.9.2. Dockerfile的概念和作用

1.9.2.1. 镜像制作方法

  1. 容器转镜像(不常用)

    docker commit [id] [Image-name]:[tag]
    
    docker save -o [压缩文件名称] [Image-name]:[tag]
    
    docker load -i [压缩文件名称]
    

    注意

    若原有镜像含有挂载文件,则commit时不会将其挂载到新制作的镜像。

    • 操作步骤
      $ docker ps -a
      
      CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS                    NAMES
      679f5de7ab12        redis               "docker-entrypoint.sh"   12 hours ago        Up 2 hours               0.0.0.0:6379->6379/tcp   my_redis
      
      # 制作一个Redis镜像名为make_redis
      $ docker commit 679f5de7 make_redis
      
      sha256:c5f603178b0cc95aeb04d3e674060d1268541d361748852d73d7eba652f0c6d3
      # 查看镜像
      $ docker images
      
      REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
      make_redis          latest              c5f603178b0c        8 hours ago         98.21 MB
      redis               latest              f0453552d7f2        32 hours ago        98.21 MB
      # 打包镜像
      $ docker save -o make-redis.tar make_redis
      # 为了还原镜像,我们先删除存在的
      $ docker rmi c5f6031
      Untagged: make_redis:latest
      Deleted: sha256:c5f603178b0cc95aeb04d3e674060d1268541d361748852d73d7eba652f0c6d3
      Deleted: sha256:88106bcdc3c35ca6ea7bdb8e7dd06d91c921a328587a0f72b87628ffea654945
      # 加载制作的新镜像
      $ docker load -i make-redis.tar
          936d71f61caa: Loading layer 3.584 kB/3.584 kB
          Loaded image: make_redis:latest
      # 查看是否成功还原
      $ docker images
          REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
          make_redis          latest              c5f603178b0c        8 hours ago         98.21 MB
          redis               latest              f0453552d7f2        32 hours ago        98.21 MB
      
  2. Dockerfile(常用方法)
    • Dockerfile是一个文本文件,包含了一行行的指令。
    • 不一定叫Dockerfile名称,可根据实际需求来。如nginx_dockerfile
    • 每一行指令构建一层镜像,基于基础镜像,最终构建出一个新的镜像。
    • Dockerfile关键字,可参考:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
      • FROM:父镜像
      • RUN:执行命令,[“command-1”, “command-2”]
      • CMD: 容器启动命令
      • COPY:复制文件
      • WORKDIR:工作目录。指定容器内的工作目录
      • ADD:添加文件

1.9.3. 案例

1.9.3.1. 案例一之CentOS安装Vim

  • 任务
    制作一个centos7镜像。保证:
    • 默认登录路径为/usr;
    • 可以使用vim
  • 步骤
    $ docker pull centos:7
    $ docker run -it --name=c1 centos:7
    # 编写Dockerfile文件
    $ vim Dockerfile
        # 定义基础镜像
        FROM centos:7
        # 作者信息
        MAINTAINER Mason
        # 执行操作
        RUN yum install -y vim
        # 设置工作目录
        WORKDIR /usr
        # 设置启动命令
        CMD ["/bin/bash"]
    # . 表示的是当前目录,不要忘记写了
    $ docker build -f Dockerfile -t test_centos:1 .
        Sending build context to Docker daemon 222.6 MB
        Step 1 : FROM centos:7
        ---> 5e35e350aded
        Step 2 : MAINTAINER Mason
        ---> Using cache
        ---> efe73e688fd0
        Step 3 : RUN yum install -y vim
        ---> Using cache
        ---> d79eb09c16dc
        Step 4 : WORKDIR /usr
        ---> Using cache
        ---> 0da2b1bca082
        Step 5 : CMD /bin/bash
        ---> Running in 697bd23b374a
        ---> a71548cf9f8e
    $ docker run -it --name c2 test_centos:1
    $ [root@aa24050fdab5 usr]# vim test.txt
    
    # 完成所有任务
    

1.9.3.2. 案例二之发布Flask应用

  • 任务

    定义Dockerfile,发布一个Hello,Flask版的Flask-Web项目

  • 步骤

    # 创建并进入flask-web目录
    $ cd flask-web
    # 写一个启动脚本 app.py
    $ vim app.py
        #app.py
        from flask import Flask
    
        app = Flask(__name__)
    
        @app.route('/')
        def index():
            return '<h1> hello, Flask </h1>'
    
        if __name__ == '__main__':
            app.run(host='0.0.0.0', port=5000, debug=True)
    # 编写Dockerfile文件,名称为flask_dockerfile
    $ vim flask_dockefile
        FROM centos:7
        # 作者信息
        MAINTAINER Mason
        # 执行操作
        RUN yum install -y python3 && yum -y install epel-release && yum install -y python-pip
        RUN pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple
        # 设置工作目录
        WORKDIR /web_app
        # 设置默认命令
        ENTRYPOINT [ "python" ]
        # 设置启动命令
        CMD ["app.py"]
    # 开始构建镜像
        $ docker build -f flask_dockerfile -t flask-web:1.0 .
        # 创建应用容器
        $ docker run -id \
        -p 5001:5000 \
        --name web_app \
        -v $PWD/flask-web:/web_app \
        flask-web:1.0
    
    # 浏览器访问容器应用
    0.0.0.0:5001
    # 完成
    

1.10. docker-compose(服务编排技术)

1.10.1. 服务编排概念

  • 目的:将一系列的容器创建自动化
  • docker-compose是一个工具。能够编排多容器分布式部署,以指令集的形式管理容器化应用的开发周期,如构建、启动、停止。
  • 基本过程
    • 利用Dockerfile文件定义运行环境镜像。
    • 使用docker-compose.yml定义组成应用的各服务。
      • 前后依赖关系
      • 容器数量等
    • 运行docker-compose up 启动应用。

1.10.2. 日常命令

  1. 修改docker-compose.yml文件后重启容器

    $ docker-compose down
    # -d参数为后台运行
    $ docker-compose up -d
    

1.10.3. 安装(Mac系统)

  • Mac系统安装Docker后会包含这个工具,直接查看下版本
$ docker-compose version
docker-compose version 1.8.1, build 878cff1

1.10.4. 实例-发布简单Nginx+Flask-web应用

注解

  • 要发布一个完整的项目就存在很多组件服务,如数据库、反向代理等,逐个启动太过麻烦了,我们可以使用docker-compose工具统一进行定义并启动。
  • 这个案例就要编排反向代理及flask两个服务应用。
# 创建工作目录
$ mkdir ~/docker-compose
$ cd ~/docker-compose
# 编写yml文件。名称是固定的。注意yaml缩进
$ vim docker-compose.yml
# 这个版本号需要与docker版本对应:https://docs.docker.com/compose/compose-file/
    version: '2'
    services:
        # 服务名称可随便取
        Nginx:
            image: nginx  #镜像名称
            ports: #端口映射,启动服务后,直接访问80端口即可(监听6000,6000会映射为5000)
                - 80:6000
            links: # 和另一个服务关联
                - flask-web
            volumes: # 配置文件
                - ./nginx/conf.d:/etc/nginx/conf.d
        flask-web: #服务应用名称,可随便取
            image: flask-web:1.0 #镜像名称,采用上一个实例的
            volumes: #应用目录
                - ../flask-web/:/web_app
            ports: #端口映射
                - "6000:5000"
$ mkdir -p ./nginx/conf.d
# Nginx相关配置
$ vim ./nginx/conf.d/server.conf
server {
    listen 6000; #监听6000端口
    access_log off;


    location / {
    proxy_pass http://flask-web:5000
    }
}
# 回到docker-compose目录,开始启动服务。
$ docker-compose up # 后面-d参数将会后台运行,这里就不加了
    Starting dockercompose_flask-web_1
    Starting dockercompose_Nginx_1
    Attaching to dockercompose_flask-web_1, dockercompose_Nginx_1
若正常启动,则直接在浏览器访问
    http://0.0.0.0

1.11. 搭建私有仓库

注解

搭建自己的仓库。上传本地镜像并从私有拉取镜像

1.11.1. 创建私有仓库

  • 拉取私有仓库镜像
    $ docker pull registry:2
    
  • 启动仓库
    $ docker run -id --name=my_hub -p 9000:5000 registry:2
    
  • 浏览器访问

    http://127.0.0.1:9000/v2/_catalog 可以看到是空的

  • 修改daemon.json

    小技巧

    Mac系统可直接客户端的配置

    ../../_images/私有仓库.jpg

1.11.2. 传并拉镜像

  • 传CentOs
# 先重新打个标记
$ docker tag centos:7 0.0.0.0:9000/centos:7.1
$ docker images
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
0.0.0.0:9000/centos   7.1                 5e35e350aded        4 months ago        203 MB
# 开始传入仓库
$ docker push 0.0.0.0:9000/centos:7.1
    The push refers to a repository [0.0.0.0:9000/centos]
    77b174a6a187: Pushed
    7.1: digest: sha256:934aed62ee9ee05733d233c679a576a1d21aee98ef809493260686aad2bd3e0a size: 529
# 浏览器访问,即可看到上传的镜像
http://127.0.0.1:9000/v2/_catalog
{
    repositories: ["centos"]
}

注意

  • 报错1:
  • 解决
    • 首先,确保添加了安全组insecure-registries:0.0.0.0:9000
    • 重启shell终端及docker服务
  • 报错2:
  • 解决
    • 重新启动容器:docker start my_hub
  • 拉取镜像
$ docker pull 0.0.0.0:9000/centos:7.1
Digest: sha256:934aed62ee9ee05733d233c679a576a1d21aee98ef809493260686aad2bd3e0a
Status: Image is up to date for 0.0.0.0:9000/centos:7.1

1.12. 结束

至此,关于docker的基础知识及命令已完成,后续会继续网络、容器集群管理、终端运维管理相关的学习。