Docker学习(一)
Docker 学习(一)
理解 Docker
基本概念:
- 镜像
- 容器
镜像
是一个特殊的文件系统,包含了容器运行时的依赖。
镜像是一层层构建的,前一层是后一层的基础。每一层构建完就不会再改变,后一层删除前一层文件的操作会保留文件,只是该文件会标记为已删除。
因为上面所说的特性,镜像是只读的。
容器
容器是镜像的实例,容器运行时在镜像层上创建一个存储层,该存储层会在容器消亡时消亡,该层中的数据也不会保留。
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用 数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。
安装配置
不使用 sudo 命令执行 Docker
因为 Docker 运行时需要特殊权限,所以默认执行命令都必须在前面加上 sudo。
不使用 sudo 命令执行 Docker 方法:把用户放进 docker 用户组里面(等同于赋予它 root 权限)。
sudo useradd -aG docker $USER # 还要注销重新登录
sudo service docker restart # 重启服务
基本命令
获取某个容器的信息
docker inspect 容器名/容器 ID
查看容器文件改变情况
docker diff 容器名/容器 ID
查看容器日志
docker logs 容器名/容器 ID
删除容器
docker rm 容器名/容器 ID
列出容器
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器
docker ps -aq # 查看所有容器,只显示容器 ID
删除镜像
docker rmi 镜像名/镜像 ID
下载/上传镜像
docker pull/push 镜像名[:TAG|@DIGEST]
创建容器
docker run
通过 Dockerfile 定制镜像
docker commit
命令可以通过容器产生镜像,但是要重复操作产生多个相同镜像却不方便,此时使用 Dockerfile 能解决这个问题。
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
使用 docker build
来构建镜像
格式为:
docker build [选项] <上下文路径/URL/->
其中常用到 -t 选项来指定构建出的镜像的名称。
当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会获得构建镜像所需的一切文件。
一般新建一个空文件夹并以该文件夹作为上下文路径来构建镜像。
例:
docker build -t myimage .
这里的“.“就是上下文路径,表示当前文件夹。
FROM 指定基础镜像
定制镜像一定要以一个镜像为基础,而 FROM 指令就是指定基础镜像,并且这是最基本的指令,并且必须是第一条指令。
RUN 执行命令
- shell 格式:
RUN <命令>
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
- exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
注:因为每个 Dockerfile 的指令都会新建一层,而层数多并不是一件有意义的事情,因此应该用 && 连接多个命令在一条 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
COPY 复制文件
COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
格式:
COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"]
ADD 更高级的复制文件
ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。
比如 <源路径> 可以是一个 URL。
在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
CMD 容器启动命令
那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。
例如 ubuntu 镜像默认的 CMD 就是 /bin/bash
。
CMD 指令的格式和 RUN 相似,也是两种格式:
- shell 格式:
CMD <命令>
- exec 格式:
CMD ["可执行文件", "参数1", "参数2"...]
- 参数列表格式:
CMD ["参数1", "参数2"...]
(在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数)
ENTRYPOINT 入口点
格式和 CMD 相同。
ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数,但当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令。
ENV 设置环境变量
格式有两种:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
环境变量可以在其他的 Dockerfile 指令里面展开。
VOLUME 定义匿名卷
格式为:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
EXPOSE 声明端口
格式为 EXPOSE <端口1> [<端口2>...]
。
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
WORKDIR 指定工作目录
格式为 WORKDIR <工作目录路径>
。
使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
USER 指定当前用户
格式:USER <用户名>
。
USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。
当然,和 WORKDIR 一样,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。
ONBUILD 为他人做嫁衣裳
格式:ONBUILD <其它指令>
。
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
一般用于维护多个镜像,这样升级只用重新构建镜像即可,而不用修改每个的 Dockerfile
参考教程
Docker——从入门到实践
Docker 开发指南——O’REILLY