Docker

Docker

fetch150zy

基于 golang 开发的容器化技术 docker

Docker

docker 核心技术

隔离性 Linux namespace

每个用户实例之间隔离,互不影响

  • pid namespace

    隔离不同用户的进程,并且不同的namespace可以有相同的pid。

  • net namespace

    实现网络隔离,默认通过veth的方式将container中的虚拟网卡同host上的docker bridge: docker0连接

  • ipc namespace

    进程交互,在IPC资源申请时加入namespace信息-每个IPC资源都有一个唯一的32位ID。

  • mnt namespace

    允许不同namespace的进程看到的文件结构不同,文件目录被隔离开。

  • uts namespace

    允许每个容器有独立的host name和domain name,使其在网络上可被视为一个独立的结点而非host上的一个进程

  • user namespace

    不同容器拥有不同user和group id。

控制组 Cgroups

控制组 – 可配额、可度量

在/cgroup目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对资源的控制。

  • blkio限制每个块设备的输入输出控制。光盘、磁盘、usb等。
  • cpu使用调度程序为cgroup任务提供cpu的访问
  • cpuacct产生cgroup任务的cpu资源报告
  • cpuset针对多核心cpu,会为cgroup任务分配单独的cpu和内存
  • devices允许或拒绝cgroup任务对设备的访问
  • freezer暂停或恢复cgroup任务
  • memory设置每个cgroup内存限制以及内存资源报告
  • net_cts标记每个网络包供cgroup使用
  • ns名称空间子空间

便携性:AUFS

支持将不同目录挂载在同一虚拟文件系统下的文件系统

支持为每一个成员目录(类似于Git branch)设置读写权限

AUFS中有类似分层的概念,对readonly权限的branch可以逻辑上进行修改(增量的,不影响readonly部分的)

实现不借助LVM,RAID将多个disk挂载在同一目录下

讲一个readonly的branch和一个writeable的branch联合在一起,live CD正是基于此方法可以在OS image不变的基础上允许用户在其上进行写操作

  • 典型的启动Linux运行需要两个FS:bootfs,rootfs

    bootfs(lxc, aufs/btrfs, kernel) -> rootfs(/dev, /proc, /bin, /etc, /usr, /tmp …)

    image

    • bootfs(boot file system)主要包含bootloader和kernel,bootloader主要引导加载kernel,当boot成功后kernel被加载到内存中后bootfs被umount。
    • rootfs(root file system)包含典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件

    image

    • readonly方式加载并检查,然后利用union mount的方式将readwrite文件系统挂载在readonly的rootfs上,并且允许叠加;这样一组readonly和一个writeable的结构构成一个container运行时态,每个FS被称为一个FS层。

    image

    由于AUFS,每一个对readonly层文件、目录的修改都只会存在于上层的writeable层中。这样由于不存在竞争,多个container可以共享readonly的FS层。所以Docker将readonly的FS层称为”image” - 对于container而言整个rootfs都是read-write的,但事实上所有的修改都写入最上层的writeable层中,image不保护用户状态,只用于模板,新建和复制使用。

    image

    上层的image依赖下层的image,因此在Docker中把下层的image称为父image,没有父image的image称为base image。因此想要从一个image中启动一个container,Docker会先加载这个image依赖的父image以及base image;用户的进程运行在writeable的layer中。所有的parent image中的数据信息以及ID、网络和lxc管理的资源限制等具体container的配置,构成一个Docker概念上的container。

    image

安全性 AppArmor,SELinux,GRSEC

  • 由kernel namespace和cgroup实现的Linux系统固有的安全标准
  • Docker Deamon的安全接口
  • Linux本身的安全加固解决方案,类似AppArmor,SELinux

Docker 快速入门

Docker安装

  • docker配置文件

    1
    2
    /ect/docker/
    /var/lib/docker/
  • 安装

    1
    2
    sudo pacman -Syu
    sudo pacman -S docker
  • 运行配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 启动docker
    sudo systemctl start docker.service
    sudo systemctl start docker
    # 开机启动
    sudo systemctl enable docker.service
    # 关闭docker
    sudo systemctl stop docker
    # 重启docker
    sudo systemctl restart docker
    # 查看docker状态
    sudo systemctl status docker
    1
    2
    3
    4
    # 查看version
    sudo docker version
    # 查看docker信息
    sudo docker info
    • 不通过root运行docker

      1
      sudo usermod -aG docker $USER

      重启后奏效

Docker镜像

基本结构

  • 基础镜像信息

    1
    FROM ubuntu
  • 维护者信息

    1
    MAINTAINER fetch150zy <Mars_zhewei@outlook.com>
  • 镜像操作指令

    1
    2
    3
    RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
    RUN apt-get update && apt-get install -y nginx
    RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
  • 容器启动时执行指令

    1
    CMD /usr/sbin/nginx

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Nginx
#
# VERSION 0.0.1
FROM ubuntu
MAINTAINER Victor Vieux <victor@docker.com>
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
# Firefox over VNC
#
# VERSION 0.3
FROM ubuntu
# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir /.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'
EXPOSE 5900
CMD ["x11vnc", "-forever", "-usepw", "-create"]
# Multiple images example
#
# VERSION 0.1
FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f
FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4
# You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.

Docker镜像操作

  • 查找获取镜像

    1
    2
    3
    4
    5
    # 查找所需镜像
    docker search hello-world
    # 拉取镜像
    docker pull hello-world
    docker image pull hello-world
  • 查看已有镜像

    1
    2
    3
    4
    5
    6
    # 查看镜像
    docker images
    docker image ls
    # 查看镜像历史信息
    docker history hello-world:latest
    docker image history hello-world:latest
  • 备份镜像

    1
    2
    docker tag hello-world:latest hello-world:v2.0
    docker image tag hello-world:latest hello-world:v1.0
  • 删除镜像

    1
    2
    docker rmi hello-world:latest
    docker image rm hello-world:latest
  • 清除未使用的镜像

    1
    docker image prune
  • 导出导入镜像

    1
    2
    3
    4
    5
    6
    # 导出tar包
    docker save -o hello-world:latest.tar.gz hello-world:latest
    docker image save -o hello-world:latest.tar.gz hello-world:latest
    # 导入
    docker load -i hello-world:latest.tar.gz
    docker image load -i hello-world:latest.tar.gz

Dockerfile操作建议

  • dockerfile尽量越简洁越好

  • 最好把dockerfile放在一个空目录,或者使用.dockerignore文件排除

  • 尽量避免安装不需要的包

  • 一个镜像只跑一个process

  • 在dockerfile可读性和镜像层次最小化之间取得平衡

  • 构建缓存

    在构建镜像时,进程将为dockerfile内每一个指定的执行步骤构建一个镜像。

    执行指令时会对镜像缓存检查,镜像是可以重复利用的。

    如果不想使用缓存,在docker build 时使用 –no-cach=true

    • 从缓存中启动一个基础镜像,执行下一条指令,与上一层所有子镜像对比,查看是否与已经存在的镜像相同,如果不同缓存失效
    • 大多数只需要简单比较dockerfile指令与其中的一个子镜像就够了
      • 对于ADD和COPY指令,镜像中的文件每个的内容将全部检查
      • docker会与已经存在的镜像文件进行校验,如果内容或元数据被更改,缓存失效
      • ADD和COPY指令缓存将不会查看容器内文件来匹配缓存

镜像文件的大小

dockerfile中的每一条指令都对应Docker镜像中的一层

exp:

1
2
3
4
FROM ubuntu:14.04
ADD run.sh /
VOLUME /data
CMD ["./run.sh"]

Dockerfile 操作建议 - 图1

构建 Docker 镜像时,对当前的文件系统造成了修改更新

  1. ADD和COPY命令,在docker build构建镜像时向容器中添加内容。如果内容添加成功,那么构建的那层镜像大小就是添加内容的大小
  2. RUN命令,如果运行的命令涉及磁盘文件更新,该层镜像大小就是文件系统的增量修改部分

联合文件系统

镜像总大小是每一层镜像大小的总和

  • 联合文件系统的性质保证相同文件的镜像层,容器仅能看到一个

镜像共享关系

  • 多个不同的docker镜像可以共享相同的镜像层

Dockerfile参数详解

  • FROM

    1
    2
    FROM <image>
    FROM <image>:<tag>

    如果想在同一个dockerfile中创建多个镜像时,可以使用多个FROM指令

  • MAINTAINER(指定维护者信息)

    1
    MAINTAINER <name>
  • RUN(运行命令)

    1
    2
    RUN <command>
    RUN ["executable", "param1", "param2"]

    第一个在shell终端中运行命令

    第二个使用exec执行,也可以指定其它终端

    RUN ["/bin/bash", "-c", "echo hello"]

  • CMD(容器启动时执行的命令)

    1
    2
    3
    CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;
    CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;
    CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

    每个dockerfile只能有一条CMD命令

  • EXPOSE(暴露的端口号)

    1
    EXPOSE <port> [<port>...]

    docker主机会自动分配一个端口转发到指定的端口

  • ENV(指定环境变量)

    1
    ENV <key> <value>
    1
    2
    3
    4
    ENV PG_MAJOR 9.3
    ENV PG_VERSION 9.3.4
    RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
    ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

    指定使用环境并在容器运行时保持

  • ADD

    1
    ADD <src> <dest>

    复制到容器中,可以是URL或tar文件(自动解压为目录)

  • COPY

    1
    COPY <src> <dest>

    复制本地主机内容(Dockerfile所在目录的相对路径)到容器中

    当使用本地目录作为源目录时,推荐使用COPY

  • ENTERPOINT

    1
    2
    ENTRYPOINT ["executable", "param1", "param2"]
    ENTRYPOINT command param1 param2(shell中执行)。

    配置容器启动后执行的命令,并且不可被docker run提供的参数覆盖

    每个dockerfile只能有一个ENTERPOINT

  • VOLUME

    1
    VOLUME ["/data"]

    创建一个可以从本地主机或其它容器挂载的挂载点,一般用来存放数据库和需要保持的数据等

  • USER

    1
    USER daemon

    指定运行容器的用户名或UID,后续的RUN也会使用指定用户

    当服务不需要管理员权限时,可以通过该命令指定运行用户,并可以在之前创建所需要的用户

  • WORKDIR

    1
    WORKDIR /path/to/workdir

    为后续的RUN、CMD、ENTERPOINT指令配置工作目录

    1
    2
    3
    4
    5
    WORKDIR /a
    WORKDIR b
    WORKDIR c
    RUN pwd
    # 最终路径为 /a/b/c
  • ONBUILD

    1
    ONBUILD [INSTRUCTION]

    配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令

    exp:

    1
    2
    3
    4
    [...]
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src
    [...]

    基于上面创建的镜像来创建新的镜像

    1
    2
    3
    4
    FROM image-A
    #Automatically run the following
    ADD . /app/src
    RUN /usr/local/bin/python-build --dir /app/src

Docker容器

Docker容器操作

  • 查看所有容器

    1
    2
    3
    4
    docker ps 		# 默认只显示启动的容器
    docker ps -a # 显示所有容器状态
    docker ps -q # 查看容器编号
    docker ps -l # 展示最近一次创建的容器状态
  • 守护进程启动容器

    1
    docker run -d --name ngx nginx:latest
  • 启动容器

    1
    2
    3
    4
    5
    docker start ngx
    # 也可一次启动多个容器
    docker start ngx ubuntu redis
    # 重新启动容器
    docker restart ngx
  • 停止容器

    1
    2
    3
    4
    5
    6
    docker stop ngx
    docker container stop ngx
    # 也可一次停止多个容器
    docker stop ngx ubuntu redis
    # sigkill
    docker kill ngx
  • 删除容器

    1
    docker rm ngx

    批量删除正在运行的容器

    1
    2
    docker rm $(docker ps -q) -f 
    -f 强制
  • 创建容器并进入

    1
    2
    3
    4
    5
    6
    docker run -it --name ngx -P nginx:latest /bin/bash
    - i 交互
    - t tty
    -- name 指定容器名
    - P 随机分配一个主机端口到容器端口的映射
    - p 指定端口映射 exp: 5000:5000

    重新进入容器

    1
    docker exec -it ngx /bin/bash
  • 通过容器创建镜像

    1
    docker commit -m "message" -a "author" ngx nginx:v1.0
  • 查看镜像容器全部信息

    1
    2
    3
    docker image inspect nginx:latest
    docker container inspect ngx
    -f 参数可以筛选出想要的信息
  • 打印容器操作事件

    1
    2
    3
    docker events -f 'event=stop' --since '3m'
    -f 过滤
    --since 按时间筛选
  • 查看容器网络端口

    1
    docker port app 5000
  • 查看容器中应用服务进程

    1
    2
    3
    $ docker top app
    PID USER COMMAND
    854 root python app.py

容器入门

绑定容器到另外一个主机/端口或者一个Unix Socket

使用 -H 能够让Docker daemon监听特殊的IP和端口

默认情况下监听unix:///var/run/docker.sock以仅允许root进行本地连接。你可以将他设置为0.0.0.0:2375或者是指定的主机IP以供所有人连接,但是不建议这么做

类似的,Docker客户端也可以使用 -H 连接一个指定端口

-H 使用以下格式来分配主机和端口

tcp://[host][:port][path] or unix://path

1
2
3
tcp://host:2375 -> TCP connection on host:2375
tcp://host:2375/path -> TCP connection on host:2375 and prepend path to all requests
unix://path/to/socket -> Unix socket located at path/to/socket

Docker以daemon模式运行

1
2
3
4
5
6
7
8
9
10
$ sudo <path to>/docker daemon -H 0.0.0.0:5555 &
# 下载一个ubuntu镜像
$ docker -H :5555 pull ubuntu
# 如果你想同时监听TCP和Unix Socket 你可以添加多个 -H
# Run docker in daemon mode
$ sudo <path to>/docker daemon -H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock &
# Download an ubuntu image, use default Unix socket
$ docker pull ubuntu
# OR use the TCP port
$ docker -H tcp://127.0.0.1:2375 pull ubuntu

起一个持续工作的进程

1
2
3
$ JOB=$(docker run -d ubuntu /bin/sh -c "while true; do echo Hello world; sleep 1; done")
$ docker logs $JOB
$ docker kill $JOB

在一个TCP端口上绑定一个服务

1
2
3
4
5
6
7
8
# Bind port 4444 of this container, and tell netcat to listen on it
$ JOB=$(docker run -d -p 4444 ubuntu:12.10 /bin/nc -l 4444)
# Which public port is NATed to my container?
$ PORT=$(docker port $JOB 4444 | awk -F: '{ print $2 }')
# Connect to the public port
$ echo hello world | nc 127.0.0.1 $PORT
# Verify that the network connection worked
$ echo "Daemon received: $(docker logs $JOB)"

管理容器的数据

docker 管理数据主要有两种方式,数据卷以及数据卷容器

数据卷是在一个或多个容器,它绕过UFS的一个专门指定的目录。数据卷为持续共享数据提供了一些有用的功能

  • 在创建容器时,卷被初始化。如果容器的基础映像包含指定的数据装入点,现有的数据复制到在卷初始化新卷
  • 数据卷可以共享和容器之间重复使用
  • 改变数据卷将立刻生效
  • 改变数据卷数据不会影响到容器
  • 即使容器本身被删除,但是数据卷依然存在
  • 数据卷的目的是持久化数据,独立于容器的声明周期。Docker因此不会自动删除卷,当你删除一个容器,也不会“垃圾回收”直到没有容器再使用
  • 添加一个数据卷

    docker run 加上 - v参数来添加一个数据卷,- v参数可以多次使用来挂载多个数据卷

    1
    $ docker run -d -P --name web -v /webapp training/webapp python app.py

    这条命令在容器中的/webapp文件夹下创建一个数据卷存储数据

    你也可以在构建镜像时在dockerfile里面定义

    数据卷默认权限是读写,你也可以设置为只读

    1
    $ docker run -d -P --name web -v /opt/webapp:ro training/webapp python app.py

    查找数据卷路径用docker inspect命令定位

    1
    $ docker inspect web
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ...
    Mounts": [
    {
    "Name": "fac362...80535",
    "Source": "/var/lib/docker/volumes/fac362...80535/_data",
    "Destination": "/webapp",
    "Driver": "local",
    "Mode": "",
    "RW": true
    }
    ]
    # 可以看见权限RW为true
  • 挂载一个主机目录作为数据卷

    挂载主机目录为数据卷,必须参照 -v hostPath:containerPath这种格式,路径必须为绝对路径,以保证容器的可移植性

    1
    2
    3
    4
    $ docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
    # 加载主机的 /src/webapp 目录到容器的 /opts/webapp 目录
    # docker 数据卷的权限为读写,你也可以设置为只读
    $ docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
  • 挂载一个数据文件作为数据卷

    - v标记也可以从主机挂载单个文件到容器中

    1
    2
    $ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
    # 这样可以记录在容器中输入过的命令了

    如果想挂载一个文件,最简单的方式是直接挂载文件的父目录

  • 创建和挂载数据卷容器

    如果你有一些持续更新的数据想在容器间共享,最好创建数据卷容器

    数据卷容器其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的

    1
    2
    3
    4
    5
    6
    7
    # 创建一个命名的数据卷容器dbdata
    $ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
    # 然后在其它容器中使用 --volume-from 来挂载dbdata容器中的数据卷
    $ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
    $ sudo docker run -d --volumes-from dbdata --name db2 training/postgres
    # 还可以使用 --volume-from 参数来从多个容器挂载多个数据卷,也可以从其它已经挂载了数据卷的容器来挂载数据卷
    $ sudo docker run -d --name db3 --volumes-from db1 training/postgres

    注意:使用 –volumes-from 参数所挂载数据卷的容器自己并不需要保持在运行状态

    如果删除了挂载的容器(包括dbdata, db1, db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 docker rm -v 命令来指定同时删除关联的容器。 这可以让用户在容器之间升级和移动数据卷

  • 备份、存储、移动数据卷

    • 备份

      1
      $ docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
    • 创建新容器

      1
      $ docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
    • 解压数据卷挂载到容器

      1
      $ docker run --volumes-from dbdata2 -v $(pwd):/backup ubuntu cd /dbdata && tar xvf /backup/backup.tar

管理容器的通信

  • 容器与宿主机采用端口映射的方式通信

    1
    2
    3
    4
    5
    6
    # 启动容器 -P 随机分配端口
    $ docker run -d -P training/webapp python app.py
    # 查看端口映射状态
    $ docker ps nostalgic_morse
    # 使用 -p 指定端口映射
    $ docker run -d -p 80:5000 training/webapp python app.py

    - p参数的其它指定方法

    1
    2
    3
    ip:hostPort:containerPort  映射指定IP的指定端口
    ip::containerPort 映射指定IP任意端口
    hostPort:containerPort。 映射所有主机IP的指定端口
  • 采用link方式通信

    为了方便建立连接,通常需要为容器起一个name,如果不起,你会发现系统会自动分配一个名字

    1
    $ docker run -d -P --name web training/webapp python app.py

    links允许容器发现另一个容器,并在期间建立一个安全的通道以便交换数据,使用–link参数来创建一个连接

    1
    2
    3
    $ docker run -d --name db training/postgres
    # 创建一个web连接到db数据库容器
    $ docker run -d -P --name web --link db:db training/webapp python app.py

    参数格式如下:

    --link <name or id>:alias alias代表你为这个链接起的一个别名

    该参数将匹配容器name并建立连接

    1
    $ docker run -d -P --name web --link db training/webapp python app.py

    使用 docker inspect定位

    1
    2
    $ docker inspect -f "{{ .HostConfig.Links }}" web
    [/db:/web/db]

    一个创建在源容器与目标容器之间的连接允许源容器提供信息给目标容器。目标容器web可以获取源容器db提供的信息,为了实现这个功能,docker在这两个容器之间创建一个稳定的通道,并且不会暴露任何端口

    • 环境变量

      当link容器时,docker会创建许多环境变量,Docker会自动创建环境变量到目标容器中去

      也会通过docker暴露源容器的所有环境变量,这些变量来自:

      • Dockerfile中ENV命令定义的环境变量
      • 在启动源容器时使用 -e --env --env-file参数附加的环境变量

      这些环境变量使程序从相关的目标容器中发现源容器

      Docker为每一个在–link参数中的容器设置了一个_NAME环境变量。

      例如:一个web容器通过--link db : webdb 连接db容器,将会在web容器中创建一个WEBDB_NAME=/web/webdb环境变量

      Docker为源容器暴露的端口限定了一组环境变量,每一个环境变量具有唯一前缀形式

      1
      <name>_PORT_<port>_<protocol>

      前缀的构成:

      • 是–link : 后面的参数(webdb)
      • 就是暴露的端口号
      • TCP / UDP

      Docker 利用这前缀格式定义了三个不同的环境变量

      prefix_ADDR 变量包含了来自URL的IP地址,

      1
      WEBDB_PORT_5432_TCP_ADDR=172.17.0.82.

      prefix_PORT 变量仅包含了URL的端口号

      1
      WEBDB_PORT_5432_TCP_PORT=5432.

      prefix_PROTO 参数包含URL的传输协议

      1
      WEBDB_PORT_5432_TCP_PROTO=tcp.

      如果容器暴露多个端口,Docker将会为每个端口创建三个环境变量

      另外,Docker也要创建一个叫 _PORT的环境变量。这个变量包含源容器URL首次暴露的IP和端口,该端口的“首次”定义为最低级数字的端口

      最后,Docker会把源容器中的环境变量暴露给目标容器作为环境变量。并且Docker会在目标容器为每个变量创建一个ENV变量。这个变量的值被设置为启动源程序Docker所用到的值

      你可以使用env命令列出具体的容器环境变量

      1
      2
      3
      4
      5
      6
      7
      8
      9
      $ docker run --rm --name web2 --link db:db training/webapp env
      . . .
      DB_NAME=/web2/db
      DB_PORT=tcp://172.17.0.5:5432
      DB_PORT_5432_TCP=tcp://172.17.0.5:5432
      DB_PORT_5432_TCP_PROTO=tcp
      DB_PORT_5432_TCP_PORT=5432
      DB_PORT_5432_TCP_ADDR=172.17.0.5
      . . .

      你可以看到Docker利用许多有关源容器的信息创建了一些列的环境变量。每一环境变量都会带有指点定义的别名,DB前缀。如果别名是db1,那么变量前缀也会变成DB1。利用这些环境变量来配置应用用在db容器上连接数据库。这样的连接方式稳定安全私有化,只有已获得连接的web容器才会有对db容器的访问权限

      一些注意事项

      与修改/etc/hosts文件不同,在环境变量中存储的IP地址信息不会随着容器的重启而更新,建议利用hosts文件来解决连接容器的IP地址问题

      这些环境变量只是为容器的第一个process设置,某些daemon后台服务,例如sshd,只有当产生连接需求时才会设置

    • 更新 /etc/hosts文件

      处理环境变量,docker在源文件中追加了host信息,这里向web容器追加

      1
      2
      3
      4
      5
      $ docker run -t -i --rm --link db:webdb training/webapp /bin/bash
      root@aed84ee21bde:/opt/webapp# cat /etc/hosts
      172.17.0.7 aed84ee21bde
      . . .
      172.17.0.5 webdb 6e5cdeb2d300 db

      我们可以在容器中使用ping命令测试链接

      1
      2
      3
      4
      5
      6
      root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
      root@aed84ee21bde:/opt/webapp# ping webdb
      PING webdb (172.17.0.5): 48 data bytes
      56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
      56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
      56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms

      如果你重启源容器,连接依然存在

      1
      2
      3
      4
      5
      6
      7
      $ docker restart db
      db
      $ docker run -t -i --rm --link db:db training/webapp /bin/bash
      root@aed84ee21bde:/opt/webapp# cat /etc/hosts
      172.17.0.7 aed84ee21bde
      . . .
      172.17.0.9 db

其它Docker操作

日志相关

  • 打印运行日志

    1
    2
    docker logs -f app
    # -f 参数可以查看容器标准输出

仓库服务相关

  • 登入登出

    1
    2
    3
    # 输入docker id 和密码
    docker login
    docker logout

    如果有自己的仓库

    1
    2
    docker login localhost:8080
    docker logout localhost:8080

Docker基本指令及用法

环境信息相关

  • info
  • version

系统运维相关

  • attach
  • build
  • commit
  • cp
  • diff
  • export
  • images
  • import

日志信息相关

仓库服务相关

搭建私有仓库

备份镜像,方便使用

如何搭建私有仓库

  • 下载仓库镜像

    1
    docker pull registry
  • 配置私有仓库/etc/docker/daemon.json

    1
    2
    3
    {
    "insecure-registries": ["192.168.10.6:5000"]
    }
  • 重启docker

    1
    systemctl restart docker
  • 创建registry容器(关联私有仓库的配置)

    1
    docker run -d -p 5000:5000 --name registry registry:latest
  • 备份镜像名字

    1
    docker tag ubuntu:latest 192.168.10.6:5000/ubuntu-copy
  • 推送镜像到私有仓库

    1
    docker push 192.168.10.6:5000/ubuntu-copy
  • 拉取私有仓库镜像

    1
    docker pull 192.168.10.6:5000/ubuntu-copy