Docker
Docker
Docker是什么:
- Docker是一个开源的应用容器引擎。
- Docker使用容器引擎解决平台依赖问题
- Docker具有类似Github的版本控制功能
- Docker具有自己的生态圈,应用以镜像的形式发布
- 使用Golang编写 采用C/S架构,包含Docker Server和Docker client
- Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。最初实现是基于 LXC,从 0.7 版本以后开始去除 LXC,转而使用自行开发的libcontainer,从 1.11 开始,则进一步演进为使用 runC 和 containerd。
Docker 和传统虚拟化方式的不同之处:
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比 传统虚拟机更为轻便
为什么要使用Docker:
- 更高效的利用系统资源
- 由于容器不需要进行硬件虚拟以及运行完整操作统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高
效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。更快速的启动时间传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间一致的运行环境开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现「这段代码在我机器上没问题啊]这类问题。更轻松的迁移更轻松的维护和扩展Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。镜像( Image )和容器( Container )的关系,就像是面向对象程序设计中的 类 和 实例一样,镜像是静态的定义,容器是镜像运行时的实体在仓库中的应用都是以镜像形式存在的,把镜像从Docker仓库中下拉到本机,以这个镜像为启动模板启动应用,就叫容器。镜像指的是以分层的、可以被LXC/libcontainer理解的文件存储格式。把应用镜像从Docker仓库下载到本地机器上,以镜像为模板,在一个容器类虚拟机中把这个应用启动,这个虚拟机叫容器支持几乎所有的linux系统,非linux系统需要通过Docker ToolBox来支持运行docker
安装Docker
-
安装方法一:配置清华大学镜像站
cd /etc/yum.repo.d/ wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo 修改docker-ce.repo文件中的baseurl中的所有https://download.docker.com 为 https://mirrors.tuna.tsinghua.edu.cn/docker-ce yum -y install docker-ce
-
安装方法二(安装最新版本):curl -sSL https://get.docker.com/ | sh 在中国访问docker官方源那速度堪比乌龟,实在受不了,我们可以使用中科大的镜像源替代
对于使用 systemd 的系统(Ubuntu 16.04+、Debian 8+、CentOS 7), 可以在配置文件 /etc/docker/daemon.json 中加入:{ "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn/"] }
然后重启systemctl restart docker其他源的帮助可以访问中科大的镜像源网站帮助:http://mirrors.ustc.edu.cn/help/
docker 镜像
- Docker镜像含有启动容器所需要的文件系统及其内容,因此,其用于创建并启动容器
- 采用分层构建机制,最底层为bootfs,其次为rootfs
- bootfs:用于系统引导的文件系统,包括bootloader和kernel,容器启动完成后被卸载以节约内存资源
- rootfs:位于bootfs之上,表现为docker容器的根文件系统
- 传统模式中,系统启动之时,内核挂载rootfs时会首先将其挂载为只读模式,完整性自检完成后将其重新挂载为读写模式
- docker中,rootfs由内核挂载为只读模式,而后通过联合挂载技术额外挂载一个可写的层
基本命令
- docker rmi $(docker images -q) 删除全部镜像
- docker search <string> 从镜像仓库中查询镜像
- dacker pull [选项][Docker Registry 地址[:端口号]/]仓库名[:标签] 拉取镜像
- docker ps 可以查看本机上所有正在运行的容器
- docker inspect + CONTAINERID 可以查看单个容器的详细信息
- docker images 显示当前主机上所有的镜像
- docker push learn/ping 把镜像推送到docker官方仓库
- docker commit +容器ID +镜像名(如:learn/ping)把容器提交为新镜像
- docker ps -l 查询最近运行的容器
- docker image ls --format "{{.ID}}: {{.Repository}}" 使用go的模板语法
- docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
- docker image rm $(docker image ls -q redis) 删除所有仓库名为 redis 的镜像
- docker image rm $(docker image ls -q -f before=mongo:3.2) 删除所有在 mongo:3.2 之前的镜像:
- docker commit --author "template" --message "change index.html" webserver nginx:v2 镜像提交
- docker diff webserver 我们修改了容器的文件,也就是改动了容器的存储层。我们可以通过 docker diff 命令看到具体的改动
- docker attach -it +containerID 进去后退出会导致容器停止
- docker exec -it +containerID bash 不会导致容器停止、推荐使用exec
- docker container prune 清理掉所有处于终止状态的容器
- docker ps --no-trunc 查看完整的container ID
- docker logs + containerID 打印日志 加-f 实时打印
- docker stats 实时查看容器所占用系统资源
docker镜像导入,导出
- docker save [OPTIONS] IMAGE [IMAGE...]: 将镜像打包压缩
- docker save -o myimages.gz [OPTIONS] IMAGE [IMAGE...] : -o指定压缩文件名
- docker load -i myimages.gz:装载镜像文件
docker构建镜像
- docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] 基于镜像重新构建一个新的镜像
- docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 给镜像重新打标签
docker上传镜像
- docker push [OPTIONS] NAME[:TAG] 上传镜像到dockerhub官方仓库
- docker login [OPTIONS][SERVER] 登录到镜像仓库,默认不指定server为dockhub官方仓库
Docker端口映射
- -p选项的使用格式
- -p <containerPort> : 将指定的容器端口映射至主机所有地址的一个动态端口
- -p <hostPort>:<containerPort>:将容器端口映射至指定的主机端口
- -p <ip>::<containerPort>:将指定的容器端口映射至主机指定<ip>的动态端口
- -p <ip>:<hostPort>:<containerPort>:将指定的容器端口映射至主机指定的ip的端口
- docker ports + name:可查看端口
- docker run --name b2 -it --rm --network container:b1 busybox 和b1共享网络空间
- **docker run --name b2 -it --rm --network host busybox ** 和宿主机共享网络空间
Docker Networking
- 6中名称空间:UTS(主机名和域名),USER(用户),Mount(挂载文件系统),IPC(进程间通信),Pid(进程IP),Net(网络,用于协议栈的隔离)
- Namespace API提供了三种系统调用接口:
- clone():创建新的进程
- setns():允许指定进程加入特定的namespace
- unshare():将指定进程移除指定的namespace
自定义docker0桥的网络属性信息:/etc/docker/daemon.json文件
{
"bip": "192.168.1.5/24",
"fixed-cidr": "10.20.0.0/16",
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "10.20.1.1",
"default-gateway-v6": "2001:db8:abcd::89",
"dns": ["10.20.1.2","10.20.1.3"]
}
核心选项为bip,即 bridge ip 之意,用于指定docker0桥的IP地址;其它选项可通过此地址计算得出
docker volumes,存储卷关联
-
为什么使用数据存储卷:关闭并重启容器,其数据不收影响,但删除容器,则其更改将会全部丢失
-
存在的问题:存储于联合文件系统中,不易于宿主机访问,容器间数据共享不便,删除容器其数据会丢失
-
解决方案:“卷“是容器上的一个或多个目录,此类目录可绕过联合文件系统,与宿主机上的某目录绑定
-
如果不指定host目录,则默认路径为/var/lib/docker/volumes/下
-
docker-managed volume
docker run -it --name bbox -v /data busybox #将容器中的/data目录挂载到宿主机的随机目录 docker inspect -f {{.Mounts}} bbox #查看bbox容器的卷、卷标识符及挂载的主机目录
-
Bind-mount Volume
docker run -it -v HOSTDIR:VOLUMEDIR --name bbox busybox ##默认主机上的目录会自动创建 docker run inspect -f {{.Mounts}} bbox ##go模板语法
-
复制使用其他容器的卷,为Docker run命令使用–volumes-from选项
docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox docker run -it --name bbox2 --volumes-from bbox1 busybox docker run --name nginx –network container:infracon –volumens-from infracon -it busybox #共享模板容器的网络和存储
Dockerfie
- 指令本身不区分大小写,但是基于规范,应该大写
- .dockerignore文件存放不需要打包的文件
- json数组中,要使用双引号
FROM命令
- FROM <repository>[:<tag>] 或 FROM <repository>@<digest>(digest为hash码)
COPY命令
- 用于从Docker主机复制文件至创建的新镜像文件
- COPY <src>…<dest>
- COPY [“<src>”,…“<dest>“]
- src:要复制的文件或目录支持使用通配符
- dest:目标路径,即正在创建的image的文件系统路径,建议为dest使用绝对路径,否则,COPY指定则以WORKDIR为其起始路径
- 文件复制准则:
- <src>必须是build上下文中的路径,不能是其父目录中的文件
- 如果src是目录,则其内部文件或子目录会被递归复制,但src目录本省不会被复制
- 如果指定了多个src,或在src中使用了通配符,则dest必须是一个目录,且必须以/结尾
- 如果dest目录事先不存在,他将会被自动创建,这包括其父目录路径
ADD命令
- 操作与COPY指令类似
- 如果src为URL且dest不以/结尾,则src指定的文件将被下载并直接被创建为dest;如果dest以/结尾,则文件名UURL指定的文件将被直接写在并保存为dest/filename
- 如果src是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于tar -xf命令,然而,通过URL获取的tar文件将不会自动展开
WORKDIR命令
-
镜像中的工作路径,WORKDIR可以指定多次,操作为就近原则
-
示例:
WORKDIR /usr/local ADD http://nginx.org/download/nginx-1.15.5.tar.gz ./src/
VOLUME命令
- 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其他容器上的卷
- VOLUME <mountpoint>或VOLUME ["<mountpoint>"]
- 如果挂载点目录路径下此前有文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中
EXPOSE命令
- 用于为容器打开指定要监听的端口以实现与外部通信
- EXPOSE <port> [/<protocol>] [<port> [/protocol]…] protocol用于指定传输层协议,可以为tcp或udp,默认为TCP协议
- EXPOSE 指令可一次指定多个端口,如:EXPOSE 11211/UDP 11211/tcp
- 默认没有指定时并不会直接暴露端口到宿主机上,要使用docker run -P 暴露Dockerfile文件中指定要EXPOSE的端口
ENV命令
- 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用
- 调用格式为$variable_name或$
- 语法:ENV <key> <value> 或ENV <key>=<value>
- 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
- 可以在docker run 中指定env 通过-e选项修改容器中的env
RUN命令
-
在docker build 过程中执行的命令,运行命令是基于基础镜像中所存在的命令
-
建议在RUN命令的时候如果有多行使用&&符,避免创建多层
-
RUN <command>:command通常是一个命令,且以“/bin/sh -c” 来运行它,这就意味着此进程在容器中的PID不为1,不能接收Unix信号,因此docker stop
命令停止容器时,次进程接收不到SIGTERM信号 -
RUN ["<executable>", “<param1>”, “<param2>”] : 此语法参数为一个JSON数组格式,其中
为要运行的命令,后面的param为传递给命令的选项或参数,然而此种格式指定的命令不会以/bin/sh -c来发起,因此常见的shell操作如变量替换以及通配符替换将不会运行,不过如果要运行的命令依赖于shell特性的话,可以将其替换为RUN [“/bin/sh”, “-c” , “executable”, “param1”] -
示例:
FROM centos RUN yum -y install epel-release && yum makecache && yum -y install nginx
CMD命令
- 类似于RUN指令,CMD指令也可以用于运行任何命令或应用程序,不过RUN指令运行于镜像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新镜像文件启动一个容器时
- CMD命令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器将终止,不过,CMD指定的命令可以被docker run的命令选项所覆盖
- 在Dockerfile中可以存在多个CMD指令,但仅最后一个生效
- CMD <command> 或 CMD ["<executable>“, “<param1>”, “<param2>”]
- CMD ["<param1>", “<param2>”] : 用于为ENTRYPOINT提供默认参数
ENTRYPOINT命令
-
类似于CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
-
与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当做参数传递给ENTRYPOINT指定的程序,不过docker run命令的
--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
-
ENTRYPOINT <command>
-
ENTRYPOINT ["<executable>", “<param1>”, “<param2>”]
-
docker run 命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后最为其参数使用
-
Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅最后一个有效
USER命令
- 用于指定运行image时或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID
- 默认情况下,container的运行身份为root
- USER <UID> | <UserName>
- 需要注意的是,UID可以为任意数字,但实践中其必须为容器的/etc/passwd中某用户的有效UID,否则docker run 命令将运行失败
HEALTHCHECK命令
-
只要容器的主进程没有停止或转向后台运行,容器就不会停止
-
HEALTHCHECK [OPTIONS] CMD command
- OPTIONS 选项可选参数
- --interval=DURATION (默认为30s)
- --timeout (默认30s)
- --start-period(等待容器初始化的时间,默认为0s)
- --retries=N(检测次数,默认为3)
- OPTIONS 选项可选参数
-
响应值:0 success 1 unhealthy 2 reserved :备用,请勿使用
-
示例:
HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1
SHELL命令
- 指定要使用的SHELL程序
STOPSIGNAL命令
- 定义停止容器的信号
- syntax:STOPSIGNAL signal
ARG命令
- docker build 创建镜像时可以通过docker build --build-arg 参数传递值到ARG
ONBUILD命令
- 用于在Dockerfile中定义一个触发器
- Dockerfile用于build镜像文件,此镜像文件可作为base image被另一个Dockerfile用作FROM指令的参数,并以此构建新的镜像文件
- 在后面的这个Dokcerfile中的FROM指令在build过程中被执行时,将会触发创建其base image的Dockerfile文件中的ONBUILD指令定义的触发器
- 语法:ONBUILD <INSTRUCTION>
- 尽管任何指令都可以注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令
- 任何包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如:ruby:2.0-onbuild
- 在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为构建过程的上下文在缺少指定的源文件时会失败
go模板语法
- docker inspect -f {{.Mount}} +Name|ID
- docker inspect -f {{.NetworkSettings.IPAddress}} +name|ID
Docker Registry
Yum创建私有registry
yum -y install docker-registry #安装私有仓库
rpm -ql docker-distribution
/etc/docker-distribution/registry/config.yml #配置文件
/usr/bin/registry
/var/lib/registry #镜像文件存目录
systemctl start docker-distribution #启动docker registry默认监听在5000端口
docker客户端默认使用HTTPS,所以需要修改配置配置文件使其可以使用HTTP
在 /etc/docker/daemon.json中加入一行 "insecure-registries": ["registry服务器的IP:5000"]
systemctl restart docker #重启docker,使配置生效
docker docker tag fk:v8 192.168.175.4:5000/fk:v8 #重新打上标签,要不然会默认推送到Dockerhub官方上去
docker push 192.168.175.4:5000/fk:v8 #上传镜像
docker守护进程
-
docker守护进程的C/S,其默认仅监听Unix Socket格式的地址,/var/run/docker.sock;如果要使用TCP套接字,可以修改/etc/docker/daemon.json文件,添加:
"hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"] ##注意如果是最后一行,末尾不要加,号
客户端也可以向docker直接传递“-H| --host”选项,访问其他主机上的docker