Tutorial-docker

    科技2026-02-18  10

    ############# # 参考资料 # ############# # 《阮一峰的Docker入门教程》 # http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html # 《Docker — 从入门到实践》 # https://www.bookstack.cn/read/docker_practice-v1.1.0/SUMMARY.md # https://github.com/yeasy/docker_practice ############# # 0.基础概念 # ############# #1. 虚拟机 #虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。 #虽然用户可以通过虚拟机还原软件的原始环境。但是,这个方案有几个缺点。 #(1)资源占用多 #虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。 #(2)冗余步骤多 #虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。 #(3)启动慢 #启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。 #2. Linux 容器 #由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。 #Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。 #由于容器是进程级别的,相比虚拟机有很多优势。 #(1)启动快 #容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。 #(2)资源占用少 #容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。 #(3)体积小 #容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。 #总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。 #3. Docker 是什么? #Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。 #Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。 #总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。 #Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。 #Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。 #4. Docker 的用途 #更高效的利用系统资源、更快速的启动时间、一致的运行环境、持续交付和部署、更轻松的迁移、更轻松的维护和扩展 #Docker 的主要用途,目前有三大类。 #(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。 #(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。 #(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。 #5. 镜像(Image) #Docker 镜像(Image),就相当于是一个 root 文件系统。 #Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。 #因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。 #镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。 #6. 容器(Container) #镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 #容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。 #每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为 容器存储层。 #容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。 #数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。 #7. 仓库(Repository) #一个 Docker Registry 中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。 #以 Ubuntu 镜像 为例,ubuntu 是仓库的名字,其内包含有不同的版本标签,如,16.04, 18.04。我们可以通过 ubuntu:16.04,或者 ubuntu:18.04 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 ubuntu,那将视为 ubuntu:latest。 #最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。除此以外,还有 CoreOS 的 Quay.io,CoreOS 相关的镜像存储在这里;Google 的 Google Container Registry,Kubernetes 的镜像使用的就是这个服务。 ################ # 1.安装Dcoker # ################ #Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。 #1. Ubuntu 安装 Docker CE #添加稳定版本的 Docker CE APT 镜像源 apt-get remove docker docker-engine docker.io #卸载旧版本 apt-get update apt-get install apt-transport-https ca-certificates curl software-properties-common #由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书 curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add - #为了确认所下载软件包的合法性,需要添加软件源的 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add #官方源 add-apt-repository "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu $(lsb_release -cs) stable" #向 source.list 中添加 Docker 软件源 add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" #官方源 #安装 Docker CE apt-get update apt-get install docker-ce #使用脚本自动安装 Docker CE 的 Edge 版本 curl -fsSL get.docker.com -o get-docker.sh sh get-docker.sh --mirror Aliyun #启动 Docker CE systemctl enable docker systemctl start docker #建立 docker 用户组 groupadd docker #建立 docker 组 usermod -aG docker $USER #将当前用户加入 docker 组 #测试 Docker 是否安装正确 docker run hello-world #2. CentOS 安装 Docker CE #https://docs.docker.com/engine/install/centos/ #使用 yum 安装 yum list installed | grep docker #查看安装了那些docker包 yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine #卸载docker旧版本 yum install -y yum-utils device-mapper-persistent-data lvm2 #安装相关工具类 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #配置docker仓库,阿里云源 yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo #中科大源 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo #官方源 #安装 Docker CE yum makecache fast #快速更新 yum 软件源缓存 yum install docker-ce #安装docker引擎 #使用脚本自动安装 curl -fsSL get.docker.com -o get-docker.sh sh get-docker.sh --mirror Aliyun #启动 Docker CE docker version #验证是否安装成功 systemctl enable docker systemctl start docker #开启docker #建立 docker 用户组 groupadd docker #建立 docker 组 usermod -aG docker $USER #将当前用户加入 docker 组 #测试 Docker 是否安装正确 docker run hello-world #3. 配置代理 #问题1:systemctl start docker-Job for docker.service failed because the control process exited with error code. #解答1:一般是由daemon文件格式编写出错引起的 #查询docker错误信息的几条命令 sudo systemctl status docker.service sudo journalctl -fu docker.service cat /var/log/daemon.log | grep docker cat /var/log/messages | grep docker vi /etc/docker/daemon.json #配置daemon.json文件 cat > /etc/docker/daemon.json << EOF { "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn", "https://dockerhub.azk8s.cn", "https://hub-mirror.c.163.com" ], "insecure-registries":["rnd-dockerhub.huawei.com"] } EOF systemctl daemon-reload #使daemon.json生效 systemctl restart docker #重启docker systemctl daemon-reload && systemctl restart docker #重启docker服务 docker info #查看docker配置 docker run hello-world #验证docker是否安装成功 #问题2:docker run hello-world-Error response from daemon: Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io #解决2:一般是代理配置有问题 #配置docker代理 Environment="HTTP_PROXY=http://<user>:<pass>@ip:port" Environment="HTTPS_PROXY=http://<user>:<pass>@ip:port" mkdir -p /etc/systemd/system/docker.service.d cd /etc/systemd/system/docker.service.d touch https-proxy.conf cat > /etc/systemd/system/docker.service.d/https-proxy.conf << EOF [Service] Environment="HTTP_PROXY=http://z00575241:zch19950329%2a@90.253.74.198:6688" Environment="HTTPS_PROXY=http://z00575241:zch19950329%2a@90.253.74.198:6688" Environment="NO_PROXY=localhost,127.0.0.1,.huawei.com" EOF #修改DNS cat >> /etc/resolv.conf << EOF nameserver 8.8.8.8 nameserver 8.8.4.4 nameserver 223.5.5.5 nameserver 223.6.6.6 EOF #修改/etc/sysconfig/docker vi /etc/sysconfig/docker OPTIONS='--selinux-enabled --log-driver=journald --registry-mirror=https://docker.mirrors.ustc.edu.cn' #修改/etc/sysconfig/selinux vi /etc/sysconfig/selinux selinux-enabled=false systemctl daemon-reload && systemctl restart docker systemctl show --property=Environment docker docker run hello-world #拉取镜像并启动容器 docker pull centos:centos7.6.1810 #拉取基础镜像 docker tag centos centos:7.6 #为镜像设置tag docker run -it centos:7.6 /bin/bash #启动容器 ############# # 2.使用镜像 # ############# #1. 获取镜像 docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] Docker 镜像仓库地址 #地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。 仓库名 #如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。 docker pull ubuntu:18.04 docker pull registry-cbu.huawei.com/euleros_docker/euleros_x86_64:2.9.3 #EulerOS_Server_V200R009C00SPC103B230 docker pull registry-cbu.huawei.com/euleros_docker/euleros_arm:2.9.3 #EulerOS_Server_V200R009C00SPC103B230 #2. 运行容器 docker run -it --rm ubuntu:18.04 bash -it #这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。 --rm #这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。 ubuntu:18.04 #这是指用 ubuntu:18.04 镜像为基础来启动容器。 bash #放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash。 exit #3. 列出镜像 docker image ls #会列出所有顶层镜像 docker image ls -a #显示包括中间层镜像在内的所有镜像 docker image ls ubuntu docker image ls ubuntu:18.04 docker image ls -f since=mongo:3.2 #希望看到在 mongo:3.2 之后建立的镜像 docker image ls -f before=mongo:3.2 #希望看到在 mongo:3.2 之前建立的镜像 docker image ls -f label=com.example.version=0.1 #以通过 LABEL 来过滤 docker system df #查看镜像、容器、数据卷所占用的空间 docker image ls -f dangling=true #无标签镜像也被称为 虚悬镜像(dangling image) ,用此命令专门显示这类镜像 docker image prune #删除虚悬镜像 docker image ls -q docker image ls --format "{{.ID}}: {{.Repository}}" #直接列出镜像结果,并且只包含镜像ID和仓库名 docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}" #以表格等距显示,并且有标题行 #4. 删除镜像 #所以并非所有的 docker image rm 都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已 #当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为 docker rmi -f 23c146def05d docker image rm 501 docker image rm centos docker image ls --digests docker image rm node@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228 docker image rm $(docker image ls -q redis) #删除所有仓库名为 redis 的镜像 docker image rm $(docker image ls -q -f before=mongo:3.2) #删除所有在 mongo:3.2 之前的镜像 ############# # 3.制作镜像 # ############# #1. 利用 commit 理解镜像构成 #使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用 #使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为 黑箱镜像 #2. 使用 Dockerfile 定制镜像 #镜像的定制实际上就是定制每一层所添加的配置、文件 #Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建 #Docker 存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像 #如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在 #Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层 #在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建 #Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以及行首 # 进行注释的格式 #因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉 FROM #指定基础镜像 RUN #执行命令 RUN <命令> #shell 格式 RUN ["可执行文件", "参数1", "参数2"] #exec 格式 FROM debian:stretch RUN buildDeps='gcc libc6-dev make wget' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps #docker build 命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker 引擎中构建的 #这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。 #一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。 docker build [选项] <上下文路径/URL/-> #使用 Dockerfile 定制镜像 docker build -t nginx:v3 . #"."表示上下文路径 #直接用 Git repo 进行构建 docker build https://github.com/twang2218/gitlab-ce-zh.git#:11.1 #用给定的 tar 压缩包构建 docker build http://server/context.tar.gz #从标准输入中读取 Dockerfile 进行构建 docker build - < Dockerfile #从标准输入中读取上下文压缩包进行构建 docker build - < context.tar.gz #3. Dockerfile 指令详解 #3.1 COPY 复制文件 COPY [--chown=<user>:<group>] <源路径>... <目标路径> COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"] COPY package.json /usr/src/app/ #COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置 COPY hom* /mydir/ COPY hom?.txt /mydir/ COPY --chown=55:mygroup files* /mydir/ COPY --chown=bin files* /mydir/ COPY --chown=1 files* /mydir/ COPY --chown=10:11 files* /mydir/ #3.2 ADD 更高级的复制文件 #所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / #如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去 ADD --chown=55:mygroup files* /mydir/ ADD --chown=bin files* /mydir/ ADD --chown=1 files* /mydir/ ADD --chown=10:11 files* /mydir/ #3.3 CMD 容器启动命令 CMD <命令> #shell 格式 CMD ["可执行文件", "参数1", "参数2"...] #exec 格式 CMD echo $HOME ==> CMD [ "sh", "-c", "echo $HOME" ] #如果使用 shell 格式的话,实际的命令会被包装为 sh -c 的参数的形式进行执行 CMD ["nginx", "-g", "daemon off;"] #3.4 ENTRYPOINT 入口点 #ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数 #场景一:让镜像变成像命令一样使用 #因为当存在 ENTRYPOINT 后,CMD 的内容将会作为参数传给 ENTRYPOINT,而这里 -i 就是新的 CMD,因此会作为参数传给 curl,从而达到了我们预期的效果 FROM ubuntu:18.04 RUN apt-get update \ && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* ENTRYPOINT [ "curl", "-s", "https://ip.cn" ] #场景二:应用运行前的准备工作 FROM alpine:3.4 ... RUN addgroup -S redis && adduser -S -G redis redis ... ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 6379 CMD [ "redis-server" ] #E3.5 NV 设置环境变量 #下列指令可以支持环境变量展开: ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD ENV <key> <value> ENV <key1>=<value1> <key2>=<value2>... #3.6 ARG 构建参数 #构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的 #Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖 ARG <参数名>[=<默认值>] #3.7 VOLUME 定义匿名卷 #为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据 #这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化 VOLUME ["<路径1>", "<路径2>"...] VOLUME <路径> VOLUME /data docker run -d -v mydata:/data xxxx #运行时可以覆盖这个挂载设置 #3.8 EXPOSE 声明端口 #EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务 #要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射 EXPOSE <端口1> [<端口2>...] #3.9 WORKDIR 指定工作目录 #使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录 #因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令 WORKDIR <工作目录路径> #3.10 USER 指定当前用户 USER <用户名>[:<用户组>] RUN groupadd -r redis && useradd -r -g redis redis USER redis RUN [ "redis-server" ] # 建立 redis 用户,并使用 gosu 换另一个用户执行命令 RUN groupadd -r redis && useradd -r -g redis redis # 下载 gosu RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" \ && chmod +x /usr/local/bin/gosu \ && gosu nobody true # 设置 CMD,并以另外的用户执行 CMD [ "exec", "gosu", "redis", "redis-server" ] #3.11 HEALTHCHECK 健康检查 #HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常 #和 CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效 HEALTHCHECK [选项] CMD <命令> #设置检查容器健康状况的命令 HEALTHCHECK NONE #如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令 FROM nginx RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* HEALTHCHECK --interval=5s --timeout=3s \ CMD curl -fs http://localhost/ || exit 1 #3.12 ONBUILD 为他人做嫁衣裳 #ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行 #Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的 ONBUILD <其它指令> FROM node:slim RUN mkdir /app WORKDIR /app ONBUILD COPY ./package.json /app ONBUILD RUN [ "npm", "install" ] ONBUILD COPY . /app/ CMD [ "npm", "start" ] #4. Dockerfile 多阶段构建 #4.1 全部放入一个 Dockerfile #镜像层次多,镜像体积较大,部署时间变长、源代码存在泄露的风险 FROM golang:1.9-alpine RUN apk --no-cache add git ca-certificates WORKDIR /go/src/github.com/go/helloworld/ COPY app.go . RUN go get -d -v github.com/go-sql-driver/mysql \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ && cp /go/src/github.com/go/helloworld/app /root WORKDIR /root/ CMD ["./app"] $ docker build -t go/helloworld:1 -f Dockerfile.one . #4.2 分散到多个 Dockerfile #部署过程较复杂 #!/bin/sh echo Building go/helloworld:build docker build -t go/helloworld:build . -f Dockerfile.build docker create --name extract go/helloworld:build docker cp extract:/go/src/github.com/go/helloworld/app ./app docker rm -f extract echo Building go/helloworld:2 docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy rm ./app #4.3 使用多阶段构建 FROM golang:1.9-alpine as builder RUN apk --no-cache add git WORKDIR /go/src/github.com/go/helloworld/ RUN go get -d -v github.com/go-sql-driver/mysql COPY app.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:latest as prod RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=0 /go/src/github.com/go/helloworld/app . CMD ["./app"] $ docker build -t go/helloworld:3 . #4.4 只构建某一阶段的镜像 #4.5 构建时从其他镜像复制文件 #4.6 构建多种系统架构支持的 Docker 镜像 — docker manifest 命令详解 #4.7 使用 BuildKit 构建镜像 #4.8 从 rootfs 压缩包导入 docker import http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz openvz/ubuntu:16.04 #创建一个 OpenVZ 的 Ubuntu 16.04 模板的镜像 #4.9 docker save 和 docker load docker image ls alpine docker save alpine -o <filename> file <filename> #输出文件类型 docker save alpine | gzip > alpine-latest.tar.gz #使用 gzip 压缩 docker load -i alpine-latest.tar.gz #加载镜像 docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load' #如果我们结合这两个命令以及 ssh 甚至 pv 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能 ############# # 3.实际操作 # ############# #1. 操作容器 #2. 访问仓库 #3. 数据管理 #4. 使用网络 #5. 高级网络配置 ################# # 4.Docker三剑客 # ################# #1. Comopose项目 #2. Machine项目 #3. Docker Swarm ############# # 5.底层实现 # ############# ############# # 6.项目实战 # ############## #2. image 文件 #Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。 #image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。 docker image ls #列出本机的所有 image 文件 docker image rm [imageName] #删除 image 文件 docker tag centos:7.6.1810 centos7.6:latest #将centos:7.6.1810修改为centos7.6:latest,原先的centos:7.6.1810仍旧存在,需要将其删除 docker rmi -f centos:centos7.6.1810 #删除centos的tag-centos7.6.1810 #3. 实例:hello world docker image pull library/hello-world #docker image pull hello-world docker container run hello-world #docker container run命令具有自动抓取 image 文件的功能。如果发现本地没有指定的 image 文件,就会从仓库自动抓取。输出提示以后,hello world就会停止运行,容器自动终止。 docker container run -it ubuntu bash docker container kill [containID] #对于那些不会自动终止的容器,必须使用docker container kill 命令手动终止 –detach -d #在后台运行容器,并且打印容器id。 –interactive -i #即使没有连接,也要保持标准输入保持打开状态,一般与 -t 连用。 –tty -t #分配一个伪tty,一般与 -i 连用。 #4. 容器文件 #image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。 docker container ls #列出本机正在运行的容器 docker container ls --all #列出本机所有容器,包括终止运行的容器 docker container rm [containerID] #终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm命令删除 #5. Dockerfile文件 #这就需要用到 Dockerfile 文件。它是一个文本文件,用来配置 image。Docker 根据 该文件生成二进制的 image 文件。 ############# # 2.制作容器 # ############# #1. 编写 Dockerfile 文件 git clone https://github.com/ruanyf/koa-demos.git #首先,在项目的根目录下,新建一个文本文件.dockerignore,写入下面的内容。代码表示,这三个路径要排除,不要打包进入 image 文件。 .git node_modules npm-debug.log #然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容。 FROM node:8.4 #该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。 COPY . /app #将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。 WORKDIR /app #指定接下来的工作路径为/app。 RUN npm install #在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。 EXPOSE 3000 #将容器 3000 端口暴露出来, 允许外部连接这个端口。 #2. 创建 image 文件 #-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。 docker image build -t koa-demo . #docker image build -t koa-demo:0.0.1,有了 Dockerfile 文件以后,就可以使用docker image build命令创建 image 文件了。 #docker image build -t koa-demo . -问题:npm ERR! network request to https://registry.npm.taobao.org/delegates failed, reason: socket hang up npm install -g cnpm --registry=https://registry.npm.taobao.org npm install nrm -g #3. 生成容器 #-i 选项指示 docker 要在容器上打开一个标准的输入接口,-t 指示 docker 要创建一个伪 tty 终端,连接容器的标准输入接口,之后用户就可以通过终端进行输入。由于 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 命令的默认 COMMAND 为 /bin/bash,因此用户的输入是基于 bash shell 执行的。 docker container run -p 8000:3000 -it koa-demo /bin/bash #docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash -p参数 #容器的 3000 端口映射到本机的 8000 端口。 -it参数 #容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。 koa-demo:0.0.1 #image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。 /bin/bash #容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。 docker container run --rm -p 8000:3000 -it koa-demo /bin/bash #以使用docker container run命令的--rm参数,在容器终止运行后自动删除容器文件 #4. CMD命令 #RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件 #CMD命令则是在容器启动后执行 #一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令 docker container run --rm -p 8000:3000 -it koa-demo:0.0.1 #5. 发布 image 文件 docker login docker image tag [imageName] [username]/[repository]:[tag] #为本地的 image 标注用户名和版本 docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1 docker image build -t [username]/[repository]:[tag] . #也可以不标注用户名,重新构建一下 image 文件 docker image push [username]/[repository]:[tag] #发布 image 文件 ############# # 3.常用命令 # ############# docker container run [containerID] #新建容器,每运行一次,就会新建一个容器 docker container start [containerID] #用来启动已经生成、已经停止运行的容器文件 docker container kill [containerID] #终止容器运行,相当于向容器里面的主进程发出 SIGKILL 信号 docker container stop [containerID] #相当于向容器里面的主进程发出 SIGTERM 信号,然后过一段时间再发出 SIGKILL 信号 docker container logs [containerID] #用来查看 docker 容器的输出,即容器里面 Shell 的标准输出。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令查看输出。 docker container exec -it [containerID] /bin/bash #用于进入一个正在运行的 docker 容器。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令进入容器。 docker container cp [containID]:[/path/to/file] . #用于从正在运行的 Docker 容器里面,将文件拷贝到本机

     

    Processed: 0.031, SQL: 9