Docker入门知识的个人笔记总结,不适合0基础的同学作为入门资料学习。
Docker利用了Linux核心中的资源分离机制,如cgroups和linux的命名空间namespace,来建立独立的容器。它和宿主机共用内核,避免了虚拟机使用自己独立操作系统所带来的开销。
cgroups提供硬件计算资源的隔离,包括cpu,内存,存储,io与网络。
命名空间隔离了工作环境,包括进程数、网络、用户ID、挂载系统等等
命名空间分为6种,不同版本的linux内核对其支持程度是不同的,具体如下:
namespace | 系统调用参数 | 隔离内容 | 最终完成的内核版本 |
---|---|---|---|
UTS | CLONE_NEWUTS | 主机名和域名 | 2.6.19 |
IPC | CLONE_NEWIPC | 信号量,消息队列与共享内存 | 2.6.19 |
PID | CLONE_NEWPID | 进程编号 | 2.6.24 |
Network | CLONE_NEWNET | 网络设备、网络栈、端口等 | 2.6.29 |
Mount | CLONE_NEWNS | 文件系统 | 2.4.19 |
User | CLONE_NEWUSER | 用户和用户组 | 3.8 |
国内大多爱用Centos和Ubuntu,部署docker服务最好使用Centos7以上或Ubuntu,Centos6的原始内核太老对Docker的支持不太好。
Docker 的核心组件包括:
镜像(Images)
容器(Containers)
Centos7的Extra仓库提供了docker-ce的安装包,但是版本可能相对老一些。
官方网站的是最新版本但是源站的yum仓库在海外,很慢。可以使用国内的镜像仓库
比如使用清华大学的镜像:
sudo yum remove docker docker-common docker-selinux docker-engine
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
sudo sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
sudo yum makecache fast
sudo yum install docker-ce
其他系统版本可参考:
https://mirror.tuna.tsinghua.edu.cn/help/docker-ce/
安装后可以进行docker环境的检查:
docker version可以查看当前docker及其内部组件的具体版本
[root@master ~]# docker version
Client: Docker Engine - Community
Version: 19.03.12
API version: 1.40
Go version: go1.13.10
Git commit: 48a66213fe
Built: Mon Jun 22 15:46:54 2020
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.12
API version: 1.40 (minimum version 1.12)
Go version: go1.13.10
Git commit: 48a66213fe
Built: Mon Jun 22 15:45:28 2020
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.2.13
GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429
runc:
Version: 1.0.0-rc10
GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
docker-init:
Version: 0.18.0
GitCommit: fec3683
在docker hub上搜索该images
从某个repository或者registry拉取镜像
列出images
创建一个新的container
启动一个或多个容器
在一个新的容器中运行一个命令
挂载至一个运行的容器
列出容器列表
获得某个容器的日志;容器的日志默认是打印至容器的tty终端的,因此需要使用该命令才能打印至宿主机的tty终端
重启一个容器
停止一个或多个容器
杀死一个或多个容器
移除一个或多个容器
Docker镜像含有启动容器所需要的的文件系统及其内容,因此,其用于创建并启动docker 容器。
位于下层的镜像被称为父镜像(parentn image),最底层的称为基础镜像(base image)
联合挂载文件系统将这些层次组织起来,常见的联合挂载系统有aufs(ubuntu默认),devicemapper(centos7默认),overlayfs等
启动容器时,docker daemon会试图从本地获取相关镜像,本地镜像不存在时,其将从Registry中下载该镜像并保存到本地
registry:registry是一个无状态的,高度可扩展的服务器应用程序,负责存储和分发docker images
Registry 用于保存docker镜像,包括镜像的层次结构和元数据。用户可以自建Registry,也可以使用官方的Docker Hub
分类:
由某个特定的docker镜像的所有迭代版本组成的镜像仓库
registry可以理解为Repository的仓库,repository是images的仓库
registry中的镜像通常由开发人员制作,而后推送至"公共"或"私有"Registry上保存,供其他人员使用,例如部署到生产环境。
docker默认的云端仓库服务。主要提供了以下功能。
可以使用如下格式的命令从指定仓库获取镜像:
docker pull [:]/[/]:
docker commit [OPTIONS] CONTAINER [REPOSITORY:[TAG]
选项 | 默认值(如果有) | Description |
---|---|---|
–author, -a | 作者 | |
–change,-c | 提交同时改变Dockerfile中的内容 | |
–message,-m | 提交message | |
–pause,-p | true | 提交期间挂起容器 |
例子:
docker commit --change=‘CMD [“httpd”, “-h /data/httpd/htdocs”, “-f”]’ -c “EXPOSE 80” bbox1 suny/busybox/httpd:v0.1
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
可以基于ID打标,或者基于名称和标签打标,还额可以基于私有Registry打标。
推倒Docker Hub时首先需要使用docker login登录,然后使用docker push
docker push USERNAME/IMAGE
docker save
docker load
docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层
如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏,这就是“写时复制(COW)”机制
关闭并重启容器,其数据不受影响,但是删除容器后,更改会全部丢失。
docker的数据读写机制带来如下问题:
解决方案:Data volumes
卷是容器上的一个或多个目录,此类目录可绕过联合文件系统,与宿主机的某目录关联。
Data volumes提供了如下一些特性以便于容器间的数据共享与持久化:
镜像好比源码,容器好比运行源码后的进程,卷好比数据。于是镜像可以重用,卷可以共享。
卷实现了源代码(镜像)和数据(卷)的分离,用户制作镜像时无须考虑镜像运行的容器所在的主机的环境。
Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同。
docker run命令使用-v选项即可使用Volume
多个容器之间可以通过如下两种方式共享数据卷。
单主机虚拟网络:容器之间可互通,但是和外界隔离
桥接式容器一般拥有两个接口,一个环回接口,一个连接至主机上某个桥设备的以太网接口。
docker daemon 启动时默认会创建一个名为docker0的网络桥,并且创建的容器为桥接式容器,其以太网接口桥接至docker0
docker0桥为NAT桥,因此桥接式容器可通过此桥接口访问外部网络,但防火墙规则阻止了一切从外部网络访问桥接式容器的请求。
docker run --rm --net bridge busybox:latest ifconfig -a
参数补充:
- --hostname HOSTNAME : 为容器指定主机名
- --dns DNS_SERVER_IP 为容器指定所使用的的dns服务器地址
- --add-host HOSTNAME:IP为容器指定本地主机名解析
Docker0为NAT桥,因此容器一般获得的是私有网络地址
可以把容器想象为宿主机NAT服务器背后的主机
如果开放容器或骑上的服务为可被外部网络访问,需要在宿主机上为其定义DNAT规则。如:
为docker run 命令使用-p选项即可实现端口映射,无需手动添加规则:
“动态端口”指的是随机端口,具体的映射结果可使用docker port命令查看。
可以使用-P或–publish-all将容器所有计划要暴露的端口全部映射至主机端口,如:
docker run -d -P --expose 2222 --expose 3333 --name web busybox:latest /bin/httpd -p 2222 -f
docker port web
如果不想使用默认的docker0桥接口,或者需要修改此桥接口的网络属性,可以通过docker daemon命令使用-b,–bip,–fixed-cidr,–default-gateway,–dns和–mtu等选项进行设定。
联盟式容器是指使用某个已存在容器的网络接口的容器,接口被联盟内的各个容器共享使用,因此联盟式容器彼此间的网络名称空间是共用的。
联盟式容器间网络名称空间虽然共用,但是其他名称空间比如User,Mount等还是隔离的
联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序lookback互相通信,或对某个已存在的容器的网络属性进行监控时才是用这种模式的网络模型。
开放式容器共享主机网络名称空间的容器,他们对主机的网络名称空间拥有全部的访问全向,包括访问哪些关键性服务,这对宿主机安全性有很大的潜在威胁。
为docker run命令使用–net host选项即可创建开放式容器,例如:
docker run -it --rm --net host busybox:latest /bin/sh
前文提到过,镜像的生成途径包括Dockerfile和基于容器制作。本节介绍Dockerfile。
Dockerfile是构建docker image的源代码。
Docker可以通过阅读Dockerfile的指令来自动构建docker images。一个Dockerfile文件只是一个包含了所有配置镜像命令的文本文件。
#开头为注释
每行为一个命令,基础格式为:指令+参数。指令是大小写不敏感的。但是将指令大写是约定俗成的惯例,它可以很好地将指令和参数区分开
docker运行dockerfile时,从上到下依次执行
第一条指令必须是FROM,以确定你需要构建镜像的基础镜像。
必须为Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像。后续的指令运行于此基准镜像所提供的运行环境。
基准镜像可以是任何可用的镜像文件。默认情况下docker build会在docker主机上查找指定的镜像文件,其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件。
语法:
用于让Dockerfile制作者提供本人的详细信息。Dockerfile并不限制MAINTAINER指令出现的位置,但是建议将其放置于FROM指令之后。
语法:
用于从Docker主机复制文件至创建的新映像文件
语法:
文件复制准则:
ADD指令类似于COPY指令,ADD支持使用TAR文件和URL路径
语法:
操作准则:
用于为Dockerfile中所有的RUN,CMD,ENTRYPOINT,COPY和ADD指定设定工作目录
语法:
如:
- WORKDIR /var/log
- WORKDIR $STATEPATH
用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其他容器上的卷。
用于为容器打开指定要监听的端口以实现与外部通信。
如:
ENV用于指明容器环境中的环境变量。
引用环境变量时可以用 v a r i a b l e n a m e 或 者 variable_name或者 variablename或者{variable_name}
${variable_name}这种语法也被一些标准的bash解释器支持
ENV =
指定docker build过程中运行的程序
RUN
RUN ["","",""]
第一种格式中,通常是一个shell命令,且以"/bin/sh -c"来运行它,这意味着此进程在容器中的PID不是1,不能接受Unix信号,因此当使用docker stop 命令停止容器的时候,此进程收不到SIGTERM信号;
第二种语法格式中的参数是一个JSON格式的数组,executable是要运行的命令,是传递给命令的选项或参数。然而,此种格式指定的命令不会以/bin/sh -c来发起,因此常见的shell操作如变量替换及通配符替换不会进行,不过要运行的命令想依赖于shell特性的话,可以将其替换为类似下面的格式。
RUN ["/bin/bash","-c","",“param1”]
类似于RUN指令,CMD指令也可以用于运行任何命令或者应用程序,但是两者的运行时间点不同。
语法:
前两种语法格式的意义同RUN
第三种则用于ENTRYPOINT指令提供默认参数
类似CMD指令的功能,用于为容器指定默认的运行程序,从而使得容器像是一个单独的可执行程序。
与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run 命令行指定的参数所覆盖,而且这些命令行参数会被当做参数传递给ENTRYPOINT指定的程序。docker run命令的–entrypoint选项的参数可以覆盖ENTRYPOINT指令指定的程序。
语法:
docker run 命令传入的命令参数会覆盖CMD指令的内容并附加到ENTRYPOINT命令最后作为其参数使用。
Dockerfile文件中可以存在多个ENTRYPOINT指令,但是仅有最后一个会生效。
RUN,CMD,ENTRYPOINT之间的区别:
用于指定运行image时的或运行Dockerfile中任何RUN、CMD、或ENTRYPOINT指令指定的程序时的用户名或者UID
默认情况下,container的运行身份是root用户。
语法:
uid需要是在/etc/passwd中有效的用户UID
用于在Dockerfile中定义一个触发器。Dockerfile用来build映像文件,这个映像也可以作为base image被另外一个Dockerfile用作FROM指令的参数,并以之构建新的映像文件,此时将会触发base image的Dockerfile文件中的ONBUILD指令定义的触发器。
ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令
使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,如ruby:2.0-onbuild
在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败。
在docker cli发送内容给docker daemon时,他会先查找.dockerignore文件中的内容。如果存在则将.dockerignore文件中的内容排除在外。
docker提供了三种flag来管理内存、cpu、和设备资源,可以在docker run和dockeer create命令中使用:
内存限制
CPU限制
devices
–ipc
–privileged
可以通过docker-distribution创建私有仓库
yum install docker-distribution
更改docker-daemon服务,使其能够默认从私有仓库拉取而不是docker hub