Docker从⼊门到实践[笔记整理][⼀]
基础命令
名称作⽤⽰例
docker systen df查看镜像、容器、数据卷所占的空间
docker images -q产⽣指定范围的id列表docker image ls -q redis
docker image rm $()批量删除指定镜像docker image rm $(docker image ls -q redis)
docker run基于镜像启动容器docker run --name webserver -d -p 80:80 nginx
docker exec进⼊容器docker exec -it webserver /bin/bash
docker diff查看容器存储层的改动docker diff webserver
docker commit将容器的存储层保存为镜像docker commit [选项] <;容器ID或容器名> [<;仓库名>[:<;标签>]] docker history具体查看镜像历史docker history nginx:v2
docker进入容器dockerfile指令
名称作⽤⽰例FROM指定基础镜像FROM scratch 指定⼀个空⽩的镜像RUN⽤来执⾏命令⾏命令的RUN ["可执⾏⽂件", "参数1", "参数2"]
COPY从构建上下⽂⽬录中 <;源路径> 的⽂件/⽬录复制到新的⼀层的镜
像内的 <⽬标路径> 位置
COPY <;源路径>... <⽬标路径>
ADD更⾼级的复制⽂件(⼏乎不⽤它)所有复制⽂件⽤COPY,仅在需要⾃动解压缩的场合使⽤ ADD
CMD容器启动命令推荐使⽤ exec 格式 CMD ["可执⾏⽂件", "参数1", "参
数2"...] 注意是双引号
ENTRYPOINT⼊⼝点1 让镜像变成像命令⼀样使⽤; 2 应⽤运⾏前的准备⼯作
ENV设置环境变量ENV <key1>=<value1> <key2>=<value2>... ARG构建参数ARG <;参数名>[=<;默认值>]
VOLUME定义匿名卷VOLUME ["<;路径1>", "<;路径2>"...] EXPOSE声明运⾏时容器提供服务端⼝E
XPOSE <;端⼝1> [<;端⼝2>...] WORKDIR指定⼯作⽬录WORKDIR <⼯作⽬录路径>
USER指定当前⽤户USER <⽤户名>
HEALTHCHECK健康检查HEALTHCHECK [选项] CMD <;命令> :设置检查容器健康状况的命令
ONBUILD为他⼈做嫁⾐裳ONBUILD <;其它指令> dockerfile
介绍
Dockerfile 是⼀个⽂本⽂件,⾥⾯包含了⼀条条的指令,每⼀条指令构建⼀层,因此每⼀条指令的内容都是描述该层如何构建。
使⽤dockerfile的好处
避免了docker commit⽅式带来的臃肿,实际应⽤中不应采⽤docker commit.
基本流程
mkdir mynginx
cd mynginx
touch Dockerfile
vim Dockerfile,写⼊
FROM nginx
RUN echo '<h1>Hello, Docker!<h1>' > /usr/share/nginx/html/index.html
构建镜像
docker build -t nginx:v3 . # 注意最后⾯有⼀个点
or docker build - < Dockerfile #从标准输⼊中读取 Dockerfile 进⾏构建
or cat Dockerfile | docker build -
or docker build server/ #⽤给定的 tar 压缩包构建
or docker build github/twang2218/gitlab-ce-zh.git#:8.14 # 直接⽤ Git repo 进⾏构建
or docker build - < # 从标准输⼊中读取上下⽂压缩包进⾏构建
正确构建
Dockerfile 中每⼀个指令都会建⽴⼀层, RUN 也不例外。每⼀个 RUN 的⾏为,
就和刚才我们⼿⼯建⽴镜像的过程⼀样:新建⽴⼀层,在其上执⾏这些命令,执⾏结束
后, commit 这⼀层的修改,构成新的镜像。
错误的⽰例
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O "dis.io/releases/redis-3.2."
RUN mkdir -p /usr/src/redis
RUN tar -xzf -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
正确的写法
FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O "dis.io/releases/redis-3.2." \
&& mkdir -p /usr/src/redis \
&& tar -xzf -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 \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
关于上下⽂
COPY ./package.json /app/
这并不是要复制执⾏ docker build 命令所在的⽬录下的 package.json ,也不是复制
Dockerfile 所在⽬录下的 package.json ,⽽是复制上下⽂(context)⽬录下的
package.json
ADD
FROM scratch
ADD /
...
CMD
shell格式: CMD echo $HOME
实际执⾏: CMD [ "sh", "-c", "echo $HOME" ]
Docker 不是虚拟机,容器中的应⽤都应该以前台执⾏,⽽不是像虚拟机、物理机⾥⾯那样,
⽤ upstart/systemd 去启动后台服务,容器内没有后台服务的概念。
CMD service nginx start
这个命令会被理解为 CMD [ "sh", "-c", "service nginx start"] ,因此主进程实际上是 sh 。
那么当 service nginx start 命令结束后, sh 也就结束了, sh 作为主进程退出了,⾃然就会令容器退出。正确的做法是直接执⾏ nginx 可执⾏⽂件,并且要求以前台形式运⾏。⽐如:
CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT
场景⼀:让镜像变成像命令⼀样使⽤
错误的⽰范
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s", "ip" ]
docker build -t myip .
docker run myip
docker run myip -i # 如果加上-i参数,就会报错
正确的⽰范
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "ip" ]
场景⼆:应⽤运⾏前的准备⼯作
启动容器就是启动主进程,但有些时候,启动主进程前,需要⼀些准备⼯作。
官⽅redis镜像
FROM alpine:3.4
.
..
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379
CMD [ "redis-server" ]
docker-entrypoint.sh
#!/bin/sh
...
# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
chown -R redis .
exec su-exec redis "$0" "$@"
fi
exec "$@"
ENV
官⽅node镜像
ENV NODE_VERSION 7.2.0
RUN curl -SLO "/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta
<" \
&& curl -SLO "/dist/v$NODE_asc" \
&& gpg --batch --decrypt -- asc \
&& grep " node-v$NODE_\$" | sha256sum -c - \
&& tar -xJf "node-v$NODE_" -C /usr/local --strip-components=
1 \
&& rm "node-v$NODE_" \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
在这⾥先定义了环境变量 NODE_VERSION ,其后的 RUN 这层⾥,多次使⽤ $NODE_VERSION 来进⾏操作定制。
可以看到,将来升级镜像构建版本的时候,只需要更新 7.2.0 即可, Dockerfile 构建维护变得更轻松了。
下列指令可以⽀持环境变量展开:
ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD 。ARG
Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令
docker build 中⽤ --build-arg <;参数名>=<;值> 来覆盖。
VOLUME
VOLUME /data
这⾥的 /data ⽬录就会在运⾏时⾃动挂载为匿名卷,任何向 /data 中写⼊的信息都不会记录进容器存储层,
从⽽保证了容器存储层的⽆状态化。当然,运⾏时可以覆盖这个挂载设置。
docker run -d -v mydata:/data xxxx
在这⾏命令中,就使⽤了 mydata 这个命名卷挂载到了 /data 这个位置,替代了Dockerfile 中定义的匿名卷的挂载配置。EXPOSE
要将 EXPOSE 和在运⾏时使⽤ -p <;宿主端⼝>:<;容器端⼝> 区分开来。 -p ,是映射宿主端⼝和
容器端⼝,换句话说,就是将容器的对应端⼝服务公开给外界访问,⽽ EXPOSE 仅仅是声明
容器打算使⽤什么端⼝⽽已,并不会⾃动在宿主进⾏端⼝映射
WORKDIR
错误的⽰例
初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写
RUN cd /app
RUN echo "hello" >
如果需要改变以后各层的⼯作⽬录的位置,那么应该使⽤ WORKDIR 指令
USER
USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层,⽤户需提前建好.
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]
HEALTHCHECK
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 localhost/ || exit 1
这⾥我们设置了每 5 秒检查⼀次(这⾥为了试验所以间隔⾮常短,实际应该相对较长),如
果健康检查命令超过 3 秒没响应就视为失败,并且使⽤ curl -fs localhost/ || exit
1 作为健康检查命令。
查看 docker inspect --format '{{json .State.Health}}' web | python -l
ONBUILD
ONBUILD 是⼀个特殊的指令,它后⾯跟的是其它指令,⽐如 RUN , COPY 等,⽽这些指令,
在当前镜像构建时并不会被执⾏。只有当以当前镜像为基础镜像,去构建下⼀级镜像的时候才会被执⾏。Dockerfile 中的其它指令都是为了定制当前镜像⽽准备的,唯有 ONBUILD 是为了帮助别⼈定制⾃⼰⽽准备的。
假设⼀个node.js的dockerfile如下
FROM node:slim
RUN mkdir /app
WORKDIR /app
COPY ./package.json /app
RUN [ "npm", "install" ]
COPY . /app/
CMD [ "npm", "start" ]
现在有其他的镜像依赖这个镜像,假设基础镜像叫my-node
FROM node:slim
RUN mkdir /app
WORKDIR /app
CMD [ "npm", "start" ]
那么其他依赖的⼦项⽬的镜像为
FROM my-node
COPY ./package.json /app
RUN [ "npm", "install" ]
COPY . /app/
基础镜像变化后,各个项⽬都⽤这个 Dockerfile 重新构建镜像,会继承基础镜像的更新
但是问题只解决了⼀半,如果这个⼦Dockerfile ⾥⾯有些东西需要调整呢?
⽐如 npm install 都需要加⼀些参数,那怎么办?这⼀⾏ RUN 是不可能放⼊基础镜像的,
因为涉及到了当前项⽬的 ./package.json ,难道⼜要⼀个个修改么?
所以说,这样制作基础镜像,只解决了原来的 Dockerfile 的前4条指令的变化问题,
⽽后⾯三条指令的变化则完全没办法处理。
⽤ONBUILD重写基础镜像
FROM node:slim
RUN mkdir /app
WORKDIR /app
ONBUILD COPY ./package.json /app
ONBUILD RUN [ "npm", "install" ]
ONBUILD COPY . /app/
CMD [ "npm", "start" ]
在⽤ONBUILD构建基础镜像的时候,这三⾏并不会被执⾏
那么⼦镜像只需
FROM my-node
当在各个项⽬⽬录中,⽤这个只有⼀⾏的 Dockerfile 构建镜像时,之前基础镜像的那三⾏ ONBUILD 就会开始执⾏,成功的将当前项⽬的代码复制进镜像、并且针对本项⽬执⾏ npm install ,⽣成应⽤镜像
参考⽂档
Docker 从⼊门到实践
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论