Docker学习

0x00前言

上篇博客留的坑还是要填的,正好开始自己的Docker之旅...

0x01 Docker安装

首先允许docker使用HTTPS

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg2 \
    software-properties-common

加入Docker官方的GPG key:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

debian系统

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

在源中加入Docker的源,然后更新系统

sudo add-apt-repository \
   "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/debian \
   $(lsb_release -cs) \
   stable"

输入命令sudo apt-get install docker-ce安装Docker,输入docker-v显示版本

Docker version 18.09.3, build 774a1f4

0x02 Docker介绍

什么是容器?

一句话来说,容器就是将软件包打包成标准化单元用于开发、交付和部署使用

  • 容器镜像是轻量的、可执行的独立软件包 ,包含软件运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。
  • 容器化软件适用于基于Linux和Windows的应用,在任何环境中都能运行。
  • 容器赋予了软件独立性,使其免受外在环境差异(例如,开发和预演环境的差异)的影响。

Docker简介和思想

简介:

  • 用户能够自动地执行重复任务,例如搭建和配置开发环境,从而解放了开发人员。
  • 用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样
  • Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性
  • 可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间
  • 避免公用的服务器,资源会容易受到其他用户的影响
  • 可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况
  •  

思想:

  • 集装箱
  • 标准化
  • 隔离

Docker镜像

Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。操作系统分为内核和用户空间。对于Linux而言,内核启动后,会挂载root文件系统为其提供用户空间支持。而Docker镜像(Image),就相当于是一个root文件系统。

Docker容器

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等 。容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。前面讲过镜像使用的是分层存储,容器也是如此。

Docker不为虚拟机,容器中的应用都应该在前台执行,没有后台服务的理念

对于容器而言,启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出

0x03 Docker基本命令

build命令和run命令在RPO浅析中已近说了大部分的命令了,所以就不再概述了

# 列举CLI命令

docker container --help

 

# 启动一个Docker镜像

docker image ls

docker images

 

# 查看Docker容器

docker container ls 

docker container ls --all

docker container ls -aq

docker ps

 

# 启动一个容器

docker start <docker-container-ID>

 

# Docker错误检查

docker logs <container_id>

# 如果启动不了容器可以在路径 /var/lib/docker/overlay 路径下面查找需要修复的docker地址,可以使用find命令查找

 

# Docker打包镜像

docker commit <container_id> <image_name>:<tag> 

 

# 复制文件进入容器内

docker cp <docker_ID>:<path>  <user-path>

 

#将文件复制进容器内

docker cp <path> <docker_ID>:<path>

 

# Docker进入容器

docker attach IMAGEID

 

或者使用命令

docker exec -ti <docker_name> /bin/bash

docker stop container-name   #停止正在运行的容器

 

# 删除一个Docker容器

docker rmi imageID

-f                        强制删除

--no-prune  不移除该镜像的过程镜像,默认移除

0x04Dockerfile

使用Dockerfile来定制化容器

容器信息

# 声明容器
FROM ubuntu:17.10
# 作者信息
MAINTAINER christa
# 书写时间
ENV REFRESHED_AT 2019-01-01
# 使用utf-8编码
ENV LANG C.UTF-8

 

RUN

接受命令作为参数并且用于创建镜像,在当前镜像的的顶层中执行命令并提交结果,新镜像用于下一步的Dockerfile。在shell形式中,可以使用\(反斜杠)将单个RUN指令继续到下一行,一般书写为:

RUN <command> (默认情况下Linux为/bin/sh -c, Windows 为 cmd /S/CWindows中运行)

CMD

主要为一个正在运行的容器提供默认执行命令,如果存在多个指令,那么只有最后一个会被执行,如果在容器运行时指定了命令,则CMD指定的默认内容会被替代。同时支持三种格式:

CMD [“executable”,"param1","param2"]  使用exec方式,推荐使用这一种

CMD command param1 param2 在/bin.sh中执行,提供需要交互的应用

CMD ["param1","param2"]  提供给 ENTRYPOINT的默认参数 

例如 CMD ["echo" ,"docker test"]CMD ["sh","-c","docker test"]

ENTRYPOINT

命令和CMD一样,区别在于ENTRYPOINT后面携带的参数不会被Docker run覆盖,而CMD会。

COPY

复制文件,将文件复制到容器内,使用本地目录为源目录时,推荐使用COPY

COPY  <src> <dest>

ADD

将复制指定的 <src> 到容器中的 <dest>。 其中 <src> 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。

ADD <src> <dest>

ENV

用用于设置环境变量,可以在容器和脚本里面直接使用

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>

EXPOSE

设置暴露出容器内部端口,不是主机的端口

EXPOSE [port]

如果需要将主机端口转换成内部端口则可以使用如下命令,例如EXPOSE 4668

docker run -d -p 127.0.0.1:8080:4668 docker/test

WORKDIR

指定容器工作目录,所执行的命令都是在当前目录下执行的

WORKDIR <path>

VOLUME

为了能够保存(持久化)数据以及共享容器之间的数据,Docker提出了Volume的概念。简单来说,Volume就是目录或文件,他可绕过默认的联合文件,而以正常的文件或者目录的形式存在于宿主机上。通常有两种方式来初始化Volume,在运行的时候使用-v来声明Volume

docker run -it --name container-test -h CONTAINER  -v /data ubuntu/bin/bash

上面的命令会将/data挂载到容器中,并绕过联合文件系统。任何在该镜像/data路劲的文件将会被复制到Volume,使用docker inspect 命令找到Volume在主机上的存储位置

docker inspect -f {{.Volumes}} container-test

通常设置Volume的权限或者为Volume初始化默认数据或者配置文件。注意:在Dockerfile的Volume指令后的任何东西都不能改变Volume,比如:

FROM debian:wheezy
RUN useradd christa
VOLUME /data
RUN touch /data/x
RUN chown -R christa:christa /data

该Docker file不能按预期那样运行,我们本来希望touch命令在镜像的文件系统上运行,但是实际上它是在一个临时容器的Volume上运行。如下所示:

FROM debian:wheezy
RUN useradd christa
RUN mkdir /data && touch /data/x
RUN chown -R christa:christa /data
VOLUME /data

Docker可以将镜像中Volume下的文件挂载到Volume下,并设置正确的权限。如果你指定Volume的主机目录将不会出现这种情况。
删除Volume

当使用过docker rm删除容器的时候任然会有孤立的Volume在占用着空间,Volume只有在如下情况才能被删除

  • 该容器是用docker rm -v命令来删除的(-v是必不可少的)
  • docker run中使用了--rm参数

Dockerfile的写法为

VOLUME  ["/dir_1", "/dir_2" ..]

 

docker-compose.yml

本次语言主要是使用的是version: '3'

docker-compose.yml文件装门为docker-compose所使用的类似于Dockerfile文件,docker-compose安装可以使用pip安装,命令为pip install docker-compose

结构

主要分为三个部分:service、networks、volumes

services主要用来定义各个容器,networks定义需要用到的networks,volumes定义services使用到的volumes

service

使用当前目录下的Dockerfile进行构建

version: '3'
services:
  web:
    build :./

假设当前文件夹名为ccweb,则构建出来的镜像名字为ccweb_web,运行出来的容器名:ccweb__web_1,若果docker-compose up的时候,ccweb_web镜像不存在,才会构建。docker-compose build会重新构建镜像,原来的镜像变成

version: '3'
services:
  web:
    build:
        context: ./
        dockerfile: owndockerfile

depends_on

指定容容器的依赖,一般是mysql,redis等,links也可以用与服务创建并启动依赖

image

制定运行的容器,有如下格式

image: redis
image: ubuntu:17.10
image: tutum/infuxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd

如果定义了build,那么image指定的就是build后的镜像的名字和tag

version: '3'
services:
  web:
    build: ./
  image: web:1.0

volumes

挂载一个目录或者一个已存在的数据卷容器, HOST:CONTAINER 格式定义共享的目录 HOST:CONTAINER:RO 定义容器只读的目录。

volumes:
    - ./conf.d:/etc/nginx/conf.d
    # nginx.conf对容器来说只读
    - ./nginx.conf:/etc/nginx/nginx.conf:ro

networks

version: '3'
services:
    ...
networks:
    - fornt-tier
    - end-tier

env_file

定义了docker_compose.yml中使用的变量,提高docker-compose.yml的灵活性

env_file: .env

env_file:
  - ./tem.env
  - ./apps/key.env

env文件中格式 key:value, 例如

RACK_ENV=securey_key
DB_PORT=3306

ports

将容器的80的端口映射到宿主机的8080端口上

ports:
    - "8080:80"
    - "172.168.0.2:8080:80"

用一个例子来说

version: '3'
services:
 nginx:
   image: nginx:1-alpine
   depends_on:
     - web
   volumes:
     - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
   ports:
     - "8080:80"
 web:
   build: .
   command: bash server.sh
   env_file:
     - .env

其文件tree结构为

├─picklecode
│  ├─nginx
│  └─web
│      ├─challenge
│      │  ├─migrations
│      │  └─templates
│      │      └─registration
│      └─core
└─thejs
    └─web
        ├─static
        └─views

创建一个镜像使用web文件夹的内容,将nginx文件夹的nginx的default.conf文件映射到/etc/nginx/conf.d/defualt.conf中,并且将端口从宿主机的8083端口映射到容器的80端口,构建一个webapp,用本地的Dockerfile进行创建,同时运行server.sh脚本,使用虚拟文件 .env进行创建

docker-compose.yml文件对配置内容的缩进非常看重,因此编写时需要特别注意

docker-compose

常用命令为

docker-compose up -d                                 创建并且启动镜像

docker-compose up -d nginx                     构建建启动nignx容器

docker-compose exec nginx bash            登录到nginx容器中

docker-compose down                              删除所有nginx容器,镜像

docker-compose ps                                   显示所有容器

docker-compose build                                构建镜像 。        

docker-compose build --no-cache 不带缓存的构建。

docker-compose events --json nginx       以json的形式输出nginx的docker日志

docker-compose pause  <container>     暂停容器

docker-compose unpause <container>恢复容器

docker-compose rm <container>           删除容器(删除前必须关闭容器)

docker-compose stop <container>         停止容器

docker-compose start <container>      启动容器

使用docker-compose或者docker run开启景象之后会有如下的显示:

pi@raspberrypi:~ $ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED                                            STATUS              PORTS                  NAMES
3086131b6343        nginx:1-alpine      "nginx -g 'daemon of…"   25 hours ago                                                       Up 25 hours         0.0.0.0:8083->80/tcp   christa_nginx_1
e1294b211aac        christa_web      "bash server.sh"         25 hours ago                                                       Up 25 hours         8000/tcp               christa_web_1

 

Reference

  1. https://docs.docker.com/get-started/
  2. http://dockone.io/article/6051
  3. http://dockone.io/article/128