赞
踩
docker pull [选项] [DockerRigistry地址[ :端口号] / ] 仓库名 [ :标签]
Docker Hub
。Docker Hub
,如果不给用户名,默认为 library
, 即官方镜像。docker pull ubuntu:16.04
docker run -it --rm ubuntu:16.04 bash
-it
: -i
是交互式操作,-t
是终端,一般一起使用。--rm
:容器退出后随之删除容器,一般不用。ubuntu:16.04
:使用镜像。bash
: 放在镜像名后面的是命令,指定交互式 shell
。docker image ls
docker system df
1.概念:没有仓库名,也没有标签的的镜像,基本是废弃不用的。
2.查看。
docker image ls -f dangling=true
3.删除所有虚悬镜像。
docker image prune
1.不加 -a 只显示顶层镜像
docker image ls -a
1.根据仓库名。
docker image ls ubuntu
2.根据仓库名和标签
docker image ls ubuntu:16.04
3.--filter
过滤参数, 简写 -f
docker image ls -f since=mongo:3.2
docker image ls -f label=com.example.version=0.1
1.显示id
docker image ls -q
1.删除
docker image rm [选项] <镜像1> [<镜像2> ....]
镜像可以是镜像id、镜像名、摘要
2.配合 ls
删除
docker image rm $(docker image ls -q -f before-mongo :3.2)
docker history nginx : v2
1.默认的镜像生成文件的名字为 Dockerfile
, 可以通过 -f
指定生成文件。
2. FROM scratch
不以任何镜像为基础。
nginx
的例子:1.新建目录 mynginx
,切入到目录。
2.新建 Dcokerfile
。
3.在 Dockerfile
文件所在的目录执行:
docker build -t nginx:v3 .
4.docker build
命令的格式:
docker build [选项] <上下文路径/URL/->
1.直接用 Git repo
构建。
$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14
这行命令指定了构建所需的 Git repo,并且指定默认的 master 分支,构建目录为 /8.14/ , 然后 Docker 就会自己去 git clone 这个项目、切换到指定分支、并进入到指定目录后开始 构建。
2.给定 tar
包构建。
$ docker build http://server/context.tar.gz
3.标准输入读取 Dockerfile
构建,输入为文件的时候。
docker build - < Dockerfile
// 或
cat Dockerfile | docker build -
这种格式没有上下文,不能使用
COPY
指令
4.标准输入压缩包(gzip, bzip2,xz)。
docker build - < context.tar.gz
Docker
在运行时分为 Docker
引擎(也就是服务端守护进程)和客户端工具。Docker
的引擎提供了一组 REST API
,被称为 Docker Remote API
,而如 docker
命令这样的客户端工具,则是通过这组 API
与 Docker
引擎交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 docker 功能,但实 际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也因为这种 C/S 设计, 所以 上下文路径 指定打包给远程服务器的一切文件。
Dockerfile
的指令都是在 上下文路径 指定的范围内运行的。如果 上下文路径 写成了当前主机的根目录,那么就会把大当前系统的所有文件传给 Docker
引擎,这是错误的。
1.Dockerfile
中每一个指令都会建立一层。
2.CMD
、ENTRYPOINT
、 HEALTHCHECK
只可以出现一次,如果写了多个,只有最后一个生效。
1.两种使用格式:
shell
格式:RUN <命令>exec
格式:RUN [ "可执行文件", "参数1", "参数2" ]
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
2.制作redi容器的一个Dockerfile
不合格的写法。
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
这里每个
RUN
指令都会新建一层
合格的写法
FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.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
1.两种格式:
COPY <源路径> ...<目标路径>
COPY [<源路径> ...<目标路径>]
目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径,工作目录可以用
WORKDIR
指令指定。
2.使用通配符格式:
COPY hom* /mydir/
COPY hom?.txt /mydir/
3.使用 COPY
指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间。
1.在复制的文件需要自动解压缩的场景下使用:
FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
2.如果复制的某个压缩文件,不需要解压缩,不要用 ADD
指令。
1.命令格式:
shell
格式:CMD <命令>
。exec
格式:CMD ["可执行文件", "参数1", "参数2" ....]
。 (使用双引号)CMD ["参数1", "参数2" ....]
。2.使用 shell
格式,下列命令会被包装成:
CMD echo $HOME
为:
CMD ["sh", "-c", "echo $HOME"]
3.容器中内没有后台服务的概念。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退 出,容器就失去了存在的意义,从而退出。
命令 CMD service nginx start
被解释成 CMD [ "sh", "-c", "service nginx start"]
,因此主进程是 sh
。那么当 service nginx start
结束了, sh
也就结 束了, sh
作为主进程退出了,自然就会令容器退出。正确的做法是: CMD ["nginx", "-g", "daemon off;"]
,nginx
为主进程。
1.ENTRYPOINT
的目的和 CMD
一样,都是在指定容器启动程序及参数。当指定了 ENTRYPOINT
后, CMD
的含义就发生了改变,不再是直接的运行其命令,而是将 CMD
的内容作为参数传给 ENTRYPOINT
指令,换句话说实际执行时,将变为:
<ENTRYPOINT> "<CMD>"
下面查询公网 ip
容器构建脚本:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s", "http://ip.cn" ]
生成的容器 myip
是没办法动态指定 curl
的参数 -i
的:
docker run myip -i
// 会报错
docker: Error response from daemon: invalid header field value "oci runtime error: con tainer_linux.go:247: starting container process caused \"exec: \\\"-i\\\": executable file not found in $PATH\"\n".
修改脚本为:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
这样构建的容器运行 docker run myip -i
就不会报错。因为 当脚本存在 ENTRYPOINT 指令后, CMD 的内容将会作为参数传给 ENTRYPOINT
,而这里 -i
就是新的 CMD
,因此会作为参数传给 curl
,从而达到了我们预 期的效果。
官方镜像 redis
中:
FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379
CMD [ "redis-server" ]
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 "$@"
构建命令 docker run -it redis id
。
1.格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2> ...
ENV VERSION=1.0 DEBUG=on \ NAME="Happy Feet"
对含有空格的值用双引号括起来
容器运行时,变量也会存在
2.在官方 node
镜像 Dockerfile
中:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta r.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components= 1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
3.支持的指令:
ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBU ILD
1.格式: ARG <参数名>[=<默认值>]
。
2.ARG
所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。
3.Dockerfile
中的 ARG
指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build
中用 --build-arg <参数名>=<值>
来覆盖。
1.格式:
VOLUME ["<路径1>", "<路径2>" ...]
VOLUME <路径>
2.容器运行时应该尽量保持容器存储层不发生写操作。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile
中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂 载,其应用也可以正常运行,不会向容器存储层写入大量数据。
VOLUME /data
运行时可以覆盖这个挂载设 置。比如:
docker run -d -v mydata:/data xxxx
使用了 mydata
这个命名卷挂载到了 /data
这个位置,替代了 Dockerfile
中定义的匿名卷的挂载配置。
1.格式:EXPOSE <端口1> <端口2>...
1.格式:WORKDIR <工作目录路径>
。
2.使用 WORKDIR
指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改 为指定的目录,如该目录不存在, WORKDIR
会帮你建立目录。
3. WORKDIR
会改变环境状态并影响以后的层。
Docker
是有分层概念的,一个 RUN
指令对于一个分层,那么在 cd
和 echo
之间就不一定是同一个进程执行环境了。
RUN cd /app
RUN echo "hello" > world.txt
1.格式:USER <用户名>
。
2.示例:
RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]
3.如果以 root
执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来 运行某个服务进程,不要使用 su
或者 sudo
,这些都需要比较麻烦的配置,而且在 TTY
缺 失的环境下经常出错。建议使用 gosu
。
# 建立 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" ]
1.格式:
HEALTHCHECK [选项] CMD <命令>
: 设置检查容器健康状况的命令。HEALTHCHECK NONE
:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令。2.支持选项:
--interval=<间隔>
:两次健康检查的间隔,默认为 30 秒;--timeout=<时长>
:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被 视为失败,默认 30 秒;--retries=<次数>
:当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3 次。3.HEALTHCHECK [选项] CMD
命令的返回值决定了该次健康检查的成功与否: 0 :成功; 1 :失败; 2 : 保留,不要使用这个值。
4.示例:
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
5.查看容器状态:
docker container ls
假设有一个基础镜像 mynode
:
FROM node:slim
RUN mkdir /app WORKDIR /app
COPY ./package.json /app
RUN [ "npm", "install" ]
COPY . /app/
CMD [ "npm", "start" ]
在构建 mynode
基础镜像时,上面的命令时立即执行比如 copy
。如果改成下面的:
FROM node:slim
RUN mkdir /app WORKDIR /app
ONBUILD COPY ./package.json /app
ONBUILD RUN [ "npm", "install" ]
ONBUILD COPY . /app/
CMD [ "npm", "start" ]
那么,在引用 mynode
镜像的其他镜像里面,比如下面的:
FROM mynode
只有在构建上面只有一行的镜像时,mynode
里面带 ONBUILD
的指令才真正的执行。
FROM golang:1.9-alpine as builder // as 第一阶段
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 // as 第二阶段
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/go/helloworld/app .
CMD ["./app"]
$ docker image ls alpine
REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest baa5d63471ea 5 weeks ago 4.803 MB
$ docker save alpine | gzip > alpine-latest.tar.gz
$ docker load -i alpine-latest.tar.gz
Loaded image: alpine:latest
[1] Docker技术入门与实战
[2] Docker 官方镜像 Dockerfile
[3] Dockerfile 最佳实践文档
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。