使用 Docker 的镜像仓库和使用 Git 类似,我们常用的命令有:
$ sudo docker images [IMAGE] # 查看本地可用镜像
$ sudo docker pull ubuntu:16.04 # 拉取指定版本(标签)的镜像
$ sudo docker pull fedora:20 # 如不指定版本,则拉取:latest
$ sudo docker search puppet # 搜索DockerHub上的镜像 (Official是否官方)
通常我们创建一个容器时,会搜索本地是否存在,若不存在会从Docker Hub搜索并 pull。比如下面这个镜像:
$ sudo docker run -i -t jamtur01/puppetmaster /bin/bash
root@<id>:# facter 探测主机信息
root@<id>:# puppet --version 验证puppet
对于之前创建的容器,我们可以修改容器,并使用 docker commit 提交修改过的容器成为一个镜像。但我并不推荐这样做(在实际应用中,不要尝试从容器创建镜像)。首先你可能需要注册一个Docker Hub帐号,然后在终端登陆提交容器。
$ sudo docker login / logout ... login $ sudo docker commit 40s3ksk3kk76 xxx/apache2 $ sudo docker commit -m"A new custom image" -a"Leon" 40s3ksk3kk76 xxx/apache2:webserver $ sudo docker images xxx/apache2 # 检查新创建的镜像
我们每一个 Dockerfile 都要放在其相应的文件夹中,且要 cd 到这个目录中构建镜像,所以在之后的小节中,我们都将不在说明 mkdir 和 cd 过程;
# Sample Nginx Web Dockerfile # Version: 0.0.1 FROM ubuntu:16.04 MAINTAINER Leon "leon@xxx.com" RUN apt-get update && apt-get install -y nginx RUN echo 'Hi, I am in your container' \ >/user/share/nginx/html/index.html EXPOSE 80 # RUN 指令默认使用: /bin/sh -c 执行; # 如果需要使用exec则使用数组方式: # RUN [ "apt-get", "install", "-y", "nginx" ]
现在我们把 Dockerfile 放到 leon_web 文件夹下,开始构建第一个镜像:
$ mkdir leon_web && cd leon_web
$ sudo docker build -t="xxx/leon_web" . (latest)
$ sudo docker build -t="xxx/leon_web:v1" .
构建失败的处理:
如果中途构建失败,又找不到原因,怎么调试?其实对每一步命令,Docker都会构建一层镜像,所以我们每一层都会得到一个镜像ID,我们使用最后一次构建成功的镜像 ID 创建一个容器,然后在容器中执行那条失败的命令调试。
当我们修正错误,继续构建的时候,基于 Docker 的构建缓存机制,将会从第一次失败的地方继续构建。
如果想从头重新构建,则使用:
$ sudo docker build --no-cache -t="xxx/leon_web" .
$docker history d1b55fd07600
$ sudo docker rmi your_user/your_image
$ sudo docker push you_hub_user/your_image
安装 Registry 非常简单(了解更多:https://docs.docker.com/registry),我们安装一个可以自启的 Registry 容器即可:
$ docker run -d -p 5000:5000 --restart=always --name registry registry.docker-cn.com/library/registry:2
$ docker tag ubuntu localhost:5000/my_image #标记本地ubuntu镜像指向Registry!
$ docker push localhost:5000/my_image # push 到仓库
$ docker pull localhost:5000/myfirstimage # 从仓库 pull
$ docker stop registry && docker rm -v registry # 关闭仓库并删除所有数据!
$ sudo docker pull domain:5000/my_image # 加上主机位置即可
$ sudo docker pull ip:5000/my_image
注:由于docker pull默认使用的是 https 协议,但有时候我们环境只有ip可用,为了让客户机用 ip 能 pull 到镜像,我们需要在客户机上执行下面的操作:
$ echo '{ "insecure-registries":["registry-server-ip:5000"] }' > /etc/docker/daemon.json
$ service docker restart # 重启即可。
网上有很多解决ip问题的方案,当我们考虑安全或者客户机比较多的情况下,我觉得还是使用域名或静态路由+https方案比较靠谱便捷,有兴趣的话可以自行搭建。
类似于RUN,但CMD是在容器启动时要运行的命令,如:
CMD ["/bin/ture"]
CMD ["/bin/bash", "-l"]
注:docker run 中的命令会覆盖CMD指令;CMD如果不使用数组形式,则Docker会在命令前加上 /bin/sh -c 执行该条指令;如果想在启动容器时运行多个进程和命令,可以使用类似 Supervisor 这样的工具;
与CMD非常类似,实际上 docker run 指定的任何参数都会被当做参数再次传递给ENTRYPOINT,如:
ENTRYPINT ["/usr/sbin/nginx"]
CMD ["-h"]
当我们启动时,如果指定了参数 -g "daemon off",
则最终执行的是:/usr/sbin/nginx -g "daemon off",如启动时不指定参数,则会执行:/usr/sbin/nginx -h;
注:如果需要,甚至可以通过 --entrypoint 覆盖 ENTRYPOINT指令;
设置指令的工作目录,可以理解为执行命令之前的 $ cd dir;
WORKDIR /opt/webapp/db
RUN bundle install
WORKDIR /opt/webapp
ENTRYPOINT [ "rackup" ]
注:可使用 -w 在运行时覆盖工作目录,如:
$ sudo docker run -ti -w /var/log ubuntu pwd /var/log
环境变量,设置的ENV将会影响后续任何 RUN 指令并在容器中持久化;
ENV RVM_PATH /home/rvm
ENV RVM_PATH=/home/rvm RVM_ARCHFLAGS="-arch i386"
在其他命令中使用环境变量:
ENV TARGET_DIR /opt/app
WORKDIR $TARGET_DIR
运行时环境变量,只在运行时有效,如:
$ sudo docker run -ti -e "WBE_PORT=8080" ubuntu env
USER nginx / user:group / uid / uid:gid # 指定镜像运行的用户,默认是root.
VOLUME ["/opt/project", "/data"]
向容器添加卷(可以是存在于一个或多个容器内的特定目录),卷存储在宿主的 /var/lib/docker/volumes 中(位置:$docker inspect -f "{{ range .Mounts }}{{.}}{{end}}" ),为持久化和共享数据提供以下主要特性:
在容器间共享和重用;
共享卷不一定要运行相应的容器;
对卷的修改会直接在卷上反映出来;
更新镜像时不会包含对卷的修改;
卷会一直存在,直到没有容器使用它们。
将构建环境下的文件和目录复制到镜像中,如:
ADD software.lic /opt/application/software.lic
ADD latest.tar.gz /var/www/web/ Docker会自动解压到web目录下;
注:复制解压不会覆盖目标文件;新建的文件和目录模式=0755,UID:GID=0:0;通过ADD添加文件或目录,会使Dockerfile中后续指令都不能继续使用之前的构建缓存。
非常类似 ADD,区别在于 COPY 只关心在构建上下文中复制本地文件,而不会做文件提取解压的工作。
LABEL version="1.0"
LABEL location="New York" type="Data center" role="Web Server"
为Docker镜像添加元数据,为避免创建过多的镜像,推荐把元数据都放在一个LABEL中。
设置停止容器时发送给系统的调用信号(内核系统调用表或SIGNAME格式中的信号)
定义在 docker build 命令运行时传递给构建运行时的变量。只能指定 Dockerfile 中定义过的参数,如:ARG build、ARG webapp_user=user
$ docker build --build-arg build=1234 -t leon/webapp .
注:不要使用 ARG 传递证书或密钥之类的安全数据。预定义的ARG变量有:HTTP_PROXY、http_proxy、HTTPS~、FTP~、NO~...
ONBULILD ADD . /app/src
ONBULILD RUN cd /app/src && make
为镜像添加触发器(trigger),当镜像被用做其他镜像的基础镜像时触发。触发器会在构建过程中插入新指令(除FROM、MAINTAINER、ONBUILD之外指令),我们可以认为这些指令紧跟FROM之后;
情景案例:
FROM ubuntu:16.04 MAINTAINER Leon "leon@weippt.com" RUN apt-get update && apt-get install -y apache2 ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ONBUILD ADD . /var/www/ EXPOSE 80 ENTRYPOINT ["/usr/sbin/apache"] CMD ["-D", "FOREGROUND"] # sudo docker build -t="test/apache2" .
现在我们可以基于 test/apache2 构建一个新的镜像:
FROM test/apache2 MAINTAINER Leon "leon@weippt.com" ENV APPLICATION_NAME webapp ENV ENVIRONMENT development # sudo docker build -t="test/webapp" .
注:观察构建过程,可以看到在 FROM 之后,Docker会插入一条 ONBUILD 指定的ADD指令。