什么是docker( Build,Ship and Run )

摘要

本文主要是为了简单介绍什么是docker、docker的基本操作而写。
本文所有资源来源于《Docker 进阶与实战》一书。

什么是docker

  • 开源容器引擎 > 管理容器、镜像
  • 轻量级虚拟化 > 容器技术本身
  • 在一些方面,性能和物理机相近 > 因为下面两条
  • 基于内核的cgroup、namespace容器技术 > 处理逻辑与内核深度融合
  • 通过libcontainer管理 > 真正意义的容器引擎
  • docker侧重于上层处理 >
  • 对层级镜像的创新 > 提高磁盘利用率

docker容器和虚拟机的区别

  • 容器和虚拟机是互补的
  • 虚拟机是用来进行硬件资源划分的完美解决方案
  • 容器是操作系统级别的虚拟化
  • 容器可以共享资源,进程级别的隔离,轻量级
  • 秒级、甚至毫秒级启动

docker核心组件

  • docker 客户端
  • docker daemon
  • docker 容器
  • docker 镜像
  • docker registry (镜像仓库)

docker 客户端

  • 典型的c/s架构
  • 客户端、服务端在一个二进制文件中(针对linux)
  • docker command、restful api

docker daemon

  • 可以理解成docker-server(docker-engine)
  • docker核心引擎
  • 接受客户端发送的请求

docker 容器

  • docker的核心内容
  • 以镜像为基础,同时提供了一个标准、隔离的执行环境
  • 环境一致性
  • Docker容器后台运行,就必须有一个前台进程
  • 容器=cgroup+namespace+rootfs+容器引擎(lxc)
    • cgroup 资源控制
    • namespace 访问隔离
    • rootfs 文件系统隔离
    • 容器引擎 生命周期控制
  • 目前所有linux容器项目都包含以上组件

什么是LXC

  • LXC用户态工具
  • Linux Container,即内核容器技术的简称(通常指这种)

docker 在此基础上做了什么

  • 跨主机部署 > 镜像
  • 以应用为中心 > Dockerfile
  • 自动构建 > Dockerfile,salt。。。
  • 版本管理 > 类似git的tag
  • 组件重用 > 镜像层级
  • 共享 > registry
  • 工具共享链 > …

容器技术(容器虚拟化)

  • 又称为容器虚拟化
  • 是一种操作系统虚拟化技术(与其他虚拟化差异比较大)
  • 轻量级虚拟化技术
  • linux内核支持

什么是容器技术(普遍认可的说法)

  • 首先要有一个相对独立的运行环境
  • 最小化其对外界的影响
  • namespace(命名空间):访问隔离
  • cgroup(控制组):资源控制

容器技术的发展史

docker 镜像

  • 是一个还没运行起来的“运行环境”
  • 轻量级、可定制的rootfs
  • 层级结构,并且可以复用
  • 自定义镜像(DOCKERFILE,COMMIT)

docker registry

  • 镜像仓库
  • 服务器级别的应用商店

docker 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
docker info
docker images
docker search|pull img_name
docker ps [-a]
docker rmi|rm
docker run [-it|-d] --name xxx img_name [cmd]
docker exec -it con_name [cmd]
docker start|stop con_name
docker logs [-ft]
docker top|stats
docker inspect img_name|con_name
docker save|load
docker build|commit
docker export|import
docker history imageid
...

build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 查看镜像
docker images [-a]
# 搜索镜像、下载镜像
docker search|pull img_name
# 创建镜像
docker build|commit
# 导出、导入镜像
docker save|load
# 导出容器、导入成镜像
docker export|import
# 删除镜像
docker rmi
# 深入镜像
docker inspect img_name
# 查看镜像构建历史
docker history imageid
# 查看镜像开放端口
docker port sinaapp

ship

1
2
3
4
5
6
7
8
9
# 从registry搜索镜像、下载镜像
docker search|pull img_name
# 导出、导入镜像
docker save|load
# 导出容器、导入成镜像
docker export|import
...
Dockerfile
Registry

run

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 查看容器
docker ps [-a]
# 删除容器
docker rm
# 启动一个容器
docker run [-it|-d] --name xxx img_name [cmd]
# 在运行的容器内运行一个新的任务
docker exec -it con_name [cmd]
# 启动、停止容器
docker start|stop con_name
# 查看容器日志
docker logs [-ft] con_name
# 查看容器性能
docker top|stats con_name
# 深入容器
docker inspect con_name
# 从容器生成镜像
docker commit
# 导出容器
docker export
...

Dockerfile

  • pull基础镜像
  • 通过dockerfile生成新的镜像
  • push新的镜像到仓库
  • 从仓库pull新的镜像
  • 通过run、compose进行部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 一个简单的Dockerfile
#################
# Version: 0.0.1
FROM ubuntu:16.04
MAINTAINER author <email>
RUN apt update
#RUN apt installedl nginx -y
RUN ["apt", "install", "-y", "nginx"]
RUN echo "Hi, I am in your container" \
> /usr/share/nginx/html/index.html
EXPOSE 80
#################
# 构建镜像
docker build -t "author/nginx:v1" .
# 使用新镜像启动容器
docker run -d -p 8080:80 --name myweb author/nginx:v1 nginx -g "daemon off;"

CMD

1
2
3
4
5
构建镜像后,情动容器默认执行的命令,如初始化环境,可以在run的时候被覆盖
CMD只能存在一个,如果多个,会运行最后一个
CMD ["/bin/ps"]
docker run -it ooppwwqq0/sa:v2 /bin/bash

ENTRYPOINT

1
2
3
4
5
6
与CMD命令有些像,但是默认不能被覆盖一般与CMD配合使用,可以配合docker run 传递参数
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]
如果想覆盖可以使用--entrypoint来覆盖

WORKDIR

1
2
3
4
5
6
7
8
9
可以用来切换目录,限定一些指令在目录下执行,也可以为最终的镜像设置工作目录
WORKDIR /opt/webapp/db
RUN touch filename
WORKDIR /opt/webapp
ENTRYPOINT ["pwd"]
可以使用-w选项覆盖
docker run -it -w /var/log ubuntu pwd

ENV

1
2
3
4
可以在镜像构建过程中设置环境变量,可以延续到以此镜像为基础的容器中,也可以用-e选项来传递环境变量
ENV WEB_PATH /home/web
WORKDIR $WEB_PATH

USER

1
2
3
4
指定启动的镜像使用的用户,默认是root
USER user:group
USER uid:gid
USER user:gid

VOLUME

1
2
3
4
5
指定容器启动的时候添加卷,一个卷可以存在一个或多个容器内的特定目录里面,可以实现将数据或者代码添加到镜像中而不是提交到镜像中,并且允许多个容器共享
VOLUME ["/opt/project", "/data"]
前面的宿主机地址挂载到后面容器的地址,后面不写会自动创建和前面一样的路径并挂载
-v选项在run的时候可以自己指定

ADD

1
2
3
4
5
6
用来将构建上下文中的文件或目录复制到镜像中
ADD conf.php /opt/app/conf/conf.php
源文件的路径可以是一个url,不能对构建上下文外的文件进行操作.
Docker通过目标地址的结尾字符判断文件源是文件还是目录,“/”结尾则源是目录,否则认为是文件。
如果源文件在本地是压缩包,如gzip、bzip2、xz,ADD可以解压到指定目录

COPY

1
2
3
4
COPY与ADD比较像,但是COPY不会做解压工作,只是单纯的拷贝。原路径要在构建上下文中,目标路径必须是一个绝对路径,如果目标目录不存在,会自动创建mkdir -p
COPY conf.d/ /etc/apache/
如果原路径是目录,那个整个目录都会拷贝到目的目录中。

ONBUILD

1
2
3
4
5
ONBUILD指令能为镜像添加触发器,当一个镜像被其他镜像用作基础镜像时,该镜像的触发器会被执行(如你的镜像需要从未准备好的位置添加代码,或者你需要执行特定于构建镜像的环境的构建脚本)
触发器会在构建过程插入新指令,我们可以认为这些指令是紧跟在FROM之后的,触发器可以是任意指令。
ONBUILD ADD . /app/src
ONBUILD RUN cd /app/src && make

docker 集群

  • compose 服务集群
  • machine 管理集群
  • openstack
  • mesos
  • swarm
  • k8s
  • rancher

docker的三大编排工具

  • compose 组装多个容器
  • machine 多平台安装docker
  • swarm 集群管理工具

docker-compose

  • 一个应用通常是由多个组件(容器)构成的
  • 定义一个应用由哪些容器组成
  • 定义容器之间的关联

  • compose将yml文件解析成docker命令参数

  • 调用相应的docker接口
  • 是对docker命令的封装
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
31
32
33
34
35
36
37
# requirements.txt
flask
redis
# app.py
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
count = redis.incr('hits')
return 'Hello from Docker! I have been seen {} times.\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
# Dockerfile
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
# docker-compose.yml
version: '2'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: "redis:alpine"