Docker是什么
Docker是一个遵从Apache2.0开源协议的应用容器引擎。她可以让开发者们打包他们自己的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux容器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口,开销极低。
Docker的应用场景
- Web应用的自动化打包和发布
- 自动化测试和持续集成、发布
Docker的优点
- 提供隔离的运行环境:文件系统隔离、网络隔离、进程号隔离、进程间通信隔离。
- 容器性能开销极低:Docker技术虽然是虚拟化技术,却几乎不消耗除容器中应用程序外的其他资源,可以达到近乎裸机的运行能力,达到秒级/微秒级的部署,一台实体机可以运行几百个docker容器。
- 容易移植:有很高的移植性,可以在任何平台运行。
Docker的缺点
Docker容器收到资源的限制包含:cpu、内存资源、磁盘I/O资源等。
Docker 安装
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
执行命令
docker -v
看到
即可说明docker安装成功
Docker 常用的相关概念解释
container:容器,是指image运行时,包含了文件资源(image展开)和系统资源。容器就是运行起来的镜像。
image:镜像,是指将应用打包好之后的存储方式,一个image包含多个layer。
layer:在Dockerfile中每一步都会产生一层layer,每一步的结果产出变成文件。
Dockerfile:一种构建image的文件的DSL。
Docker 的使用
搜索镜像
docker search imageName
可以看到可用的image列表
然后可以选择需要的镜像进行安装。
拉取镜像
docker pull redis:latest
看到
说明安装完成了。
运行镜像
开启redis服务
docker run -itd --name redis -p 6379:6379 redis
参数说明:-p 6379:6379 映射容器服务的6379端口映射到宿主机的6379端口。外部可以通过宿主机ip:6379访问到redis的服务。
docker常用命令
搜索镜像
docker search
拉取镜像到本地
docker pull image:tag
查看本地镜像
docker images
删除镜像
docker rmi imageName
运行
docker run
给镜像打标签
docker tag oldTag newTag
运行容器
docker run
进入容器
docker exec attach
封装容器为镜像
docker commit containeName iamgeName:tagName
暂停容器的运行
docker pause containeName
恢复容器的运行
docker unpause containeName
停止容器的运行
docker stop containeName
开始运行容器
docker start containeName
查询所有的容器
docker ps -a
查询查询 run 状态的和 pause 状态的容器
docker ps
检查这个容器里的各项信息
docker inspect containeName
删除容器
docker rm containeName
删除所有容器
docker rm `docker ps -a -q` -f
Docker的结构
Docker使用的是客户端-服务器(c/s)的架构模式,使用远程API来管理和创建Docker容器。Docker容器通过Docker镜像来创建。
相关概念:
Docker 守护进程(daemon)是Docker架构中运行在后台的守护进程,运行在宿主机上,用户不能直接操作daemon,只能通过docker client转达。
Docker 客户端(client)通过命令行或者其他工具使用Docker API
Docker仓库(registry)用来保存镜像,可以理解为代码控制中的代码仓库
Docker核心技术和原理
我们知道Docker核心是一个操作系统的虚拟化方法,那么从虚拟化的四个方面:隔离性、可配额/可度量、便携性、安全性来详细介绍。
隔离性
每个用户实例之间互相隔离,互不影响。一般的硬件虚拟化方法给出的是VM,而LXC给出的是container,就是kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace将container的进程、网络、消息、文件系统、UTS(“UNIX Time-sharing System”)和用户空间隔离开来。
Pid namespace
不同的用户进程就是通过pid namespace隔离开来,且不同的namespace中可以有相同的pid。所有的LXC进程在Docker中的父进程为docker进程,每一个LXC都有不同的namespace。同时允许嵌套,很容易实现docker in docker.
- 每个 namespace 中的 pid 是有自己的 pid=1 的进程(类似 /sbin/init 进程)
- 每个 namespace 中的进程只能影响自己的同一个 namespace 或子 namespace 中的进程
- 因为 /proc 包含正在运行的进程,因此在 container 中的 pseudo-filesystem 的 /proc 目录只能看到自己 namespace 中的进程
- 因为 namespace 允许嵌套,父 namespace 可以影响子 namespace 的进程,所以子 namespace 的进程可以在父 namespace 中看到,但是具有不同的 pid
Net namespace
有了pid namespace之后,每一个namespace中的pid能够互相隔离,但是网络端口还是共享host的端口。网络隔离是通过net namespace实现的, 每个 net namespace 有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个 container 的网络就能隔离开来。 docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge 连接在一起。
Ipc namespace
container中进程交互还是采用的Linux的常用的进程间的交互方式(interprocess communication-IPC),包括常见的信号量、消息队列和共享内存。
Mnt namespace
类似chroot,将一个进程放到另一个特定的目录执行。mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。
Uts namespace
UTS (“UNIX Time-sharing System”) namespace 允许每个 container 拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。
user namespace
每一个container可以有不同的user和group ID,也就是说可以在container内部用container内部的用户执行程序而非host上的用户。
可配额/可度量- control groups(cgroups)
cgroups实现了对资源的配额和度量。cgroups的使用非常简单,提供类似文件的接口,在/cgroups目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对该进程的资源控制。
groups可以限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系统的资源,以下是每个子系统的详细说明:
- blkio — 块存储配额 » this subsystem sets limits on input/output access to and from block devices such as physical drives (disk, solid state, USB, etc.).
- cpu — CPU时间分配限制 » this subsystem uses the scheduler to provide cgroup tasks access to the CPU.
- cpuacct — CPU资源报告 » this subsystem generates automatic reports on CPU resources used by tasks in a cgroup.
- cpuset — CPU绑定限制 » this subsystem assigns individual CPUs (on a multicore system) and memory nodes to tasks in a cgroup.
- devices — 设备权限限制 » this subsystem allows or denies access to devices by tasks in a cgroup.
- freezer — cgroup停止/恢复 » this subsystem suspends or resumes tasks in a cgroup.
- memory — 内存限制 » this subsystem sets limits on memory use by tasks in a cgroup, and generates automatic reports on memory resources used by those tasks.
- net_cls — 配合tc进行网络限制 » this subsystem tags network packets with a class identifier (classid) that allows the Linux traffic controller (tc) to identify packets originating from a particular cgroup task.
- net_prio — 网络设备优先级 » this subsystem provides a way to dynamically set the priority of network traffic per network interface.
- ns — 资源命名空间限制 » the namespace subsystem.
便携性:AUFS
AUFS(AnotherUnionFS)是一种Union FS,简单来说就是支持将不同目录挂载到同一个虚拟文件系统(unite several directories into a single virtual filesystem)下的文件系统。在Docker中,初始化时将 rootfs 以readonly方式加载并检查,接下来利用 union mount 的方式将一个 readwrite 文件系统挂载在 readonly 的rootfs之上,并且允许再次将下层的 FS(file system) 设定为readonly 并且向上叠加, 这样一组readonly和一个writeable的结构构成一个container的运行时态, 每一个FS被称作一个FS层。
安全性
There are four major areas to consider when reviewing Docker security:
- the intrinsic security of the kernel and its support for namespaces and cgroups;
- the attack surface of the Docker daemon itself;
- loopholes in the container configuration profile, either by default, or when customized by users.
- the “hardening” security features of the kernel and how they interact with containers.
由于安全性术语非常具体的技术,这里不再班门弄斧了,请直接参阅Docker官方文档
Docker的应用场景
场景一:
不同的应用程序可能会有不同的应用环境,比如.net开发的网站和php开发的网站依赖的软件就不一样,如果把他们依赖的软件都安装在一个服务器上就要调试很久,而且很麻烦,还会造成一些冲突。比如IIS和Apache访问端口冲突。这个时候你就要隔离.net开发的网站和php开发的网站。常规来讲,我们可以在服务器上创建不同的虚拟机在不同的虚拟机上放置不同的应用,但是虚拟机开销比较高。docker可以实现虚拟机隔离应用环境的功能,并且开销比虚拟机小,小就意味着省钱了!
场景二:
我们在本地测试部署hadoop或者ceph存储集群的时候用的是centos,但是生产环境服务器上的系统都是Ubuntu,运维在按照我们的安装文档从开发测试环境转移到生产环境的时候就会遇到一些centos转Ubuntu的问题。这时候我们使用docker就可以把开发环境直接封装给运维,运维直接部署你给的docker就好了,而且部署速度快,可以帮助我们快速交付。
Dockerfile
Docker可以通过Dockerfile的内容来自动构建镜像。Dockerfile是一个包含创建镜像所有命令的文本文件。通过docker build命令可以根据Dockerfile的内容构建镜像。
下面逐个介绍Dockerfile的指令选项
-
FROM
用法:
FROM <image>
FROM指定构建镜像的基础镜像,如果本地没有指定的镜像,则会自动从Docker的公共库pull镜像下来。
FROM必须是Dockerfile中非注释的第一个指令,即Dockerfile从FROM语句开始。
FROM语句可以出现多次,即创建多个镜像。
-
MAINTAINER
用法:
MAINTAINER <name>
指定创建镜像的用户
-
RUN
用法:
RUN RUN "executable", "param1", "param2"
每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像,后续的RUN都在之前RUN提交后的镜像为基础,镜像是分层的,可以通过一个镜像的任何一个历史提交点来创建,类似源码的版本控制。
exec 方式会被解析为一个 JSON 数组,所以必须使用双引号而不是单引号。exec 方式不会调用一个命令 shell,所以也就不会继承相应的变量,如:
RUN [ "echo", "$HOME" ]
这种方式是不会达到输出 HOME 变量的,正确的方式应该是这样的
RUN [ "sh", "-c", "echo", "$HOME" ]
RUN产生的缓存在下一次构建的时候是不会失效的,会被重用,可以使用–no-cache选项,即docker build --no-cache,如此便不会缓存。
-
CMD
CMD有三种使用方式:
CMD "executable","param1","param2" CMD "param1","param2" CMD command param1 param2 (shell form)
CMD指定在 Dockerfile 中只能使用一次,如果有多个,则只有最后一个会生效。
CMD的目的是为了在启动容器时提供一个默认的命令执行选项。如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。
-
EXPOSE
用法:
EXPOSE <port> [<port>...]
告诉 Docker 服务端容器对外映射的本地端口,需要在 docker run 的时候使用-p或者-P选项生效。
-
ENV
用法:
ENV <key> <value> # 只能设置一个变量 ENV <key>=<value> ... # 允许一次设置多个变量
指定一个环节变量,会被后续RUN指令使用,并在容器运行时保留。
例子:
ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy
等同于
ENV myName John Doe ENV myDog Rex The Dog ENV myCat fluffy
-
ADD
用法:
DD <src>... <dest>
ADD复制本地主机文件、目录或者远程文件 URLS 从 并且添加到容器指定路径中 。
支持通过 GO 的正则模糊匹配,具体规则可参见 Go filepath.Match
ADD hom* /mydir/ # adds all files starting with "hom" ADD hom?.txt /mydir/ # ? is replaced with any single character
- 路径必须是绝对路径,如果 不存在,会自动创建对应目录
- 路径必须是 Dockerfile 所在路径的相对路径
- 如果是一个目录,只会复制目录下的内容,而目录本身则不会被复制
-
COPY
用法:
COPY <src>... <dest>
COPY复制新文件或者目录从 并且添加到容器指定路径中 。用法同ADD,唯一的不同是不能指定远程文件 URLS。
-
ENTRYOINT
ENTRYPOINT "executable", "param1", "param2" ENTRYPOINT command param1 param2 (shell form)
配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,而CMD是可以被覆盖的。如果需要覆盖,则可以使用docker run --entrypoint选项。
每个 Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效。
-
VOLUME
用法:
VOLUME ["/data"]
创建一个可以从本地主机或其他容器挂载的挂载点。
-
USER
用法:
USER daemon
指定运行容器时的用户名或 UID,后续的RUN、CMD、ENTRYPOINT也会使用指定用户。
-
WORKDIR
WORKDIR /path/to/workdir
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。
WORKDIR /a WORKDIR b WORKDIR c RUN pwd
最终路径是
/a/b/c
WORKDIR指令可以在ENV设置变量之后调用环境变量:
ENV DIRPATH /path WORKDIR $DIRPATH/$DIRNAME
最终路径则为
/path/$DIRNAME
-
ONBUILD
ONBUILD [INSTRUCTION]
配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
Dockerfile Example
# 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.
参考目录:
https://docs.docker.com/engine/security/
https://tiewei.github.io/posts/howto-use-cgroup
欢迎关注我的公众号
本文由博客群发一文多发等运营工具平台 OpenWrite 发布