目录
一、镜像工作原理
二、镜像管理
二、Dockerfile
三、构建部署Nginx
四、构建部署Java网站
镜像:
1. 一个分层存储的文件:
优点:易于扩展、优化存储空间
2. 一个软件的环境
3. 一个镜像可以用于创建多个容器
4. 一种标准化的交付
一、镜像工作原理
镜像不是一个单一的文件,而是有多层构成。可以通过 docker history 查看镜像中各层内容及大小,每层对应着 Dockerfile中的一条指令。
$ docker history nginx:1.14
IMAGE CREATED CREATED BY SIZE COMMENT
86898218889a 3 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
3 weeks ago /bin/sh -c #(nop) STOPSIGNAL [SIGTERM] 0B
3 weeks ago /bin/sh -c #(nop) EXPOSE 80/tcp 0B
3 weeks ago /bin/sh -c ln -sf /dev/stdout /var/log/nginx… 22B
3 weeks ago /bin/sh -c set -x && apt-get update && apt… 53.7MB
3 weeks ago /bin/sh -c #(nop) ENV NJS_VERSION=1.14.0.0.… 0B
3 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.14.0-… 0B
3 weeks ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B
3 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
3 weeks ago /bin/sh -c #(nop) ADD file:e6ca98733431f75e9… 55.3MB
容器其实是在镜像的最上面加了一层读写层,在运行的容器中有文件改动时,会先从镜像里把要写的文件复制到容器自己的文件系统中,都会写到这个读写层。如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作的,并不会修改镜像的源文件,这种方式提高了磁盘利用率。
若想持久化这些改动,可以通过 docker commit 将容器保存成一个新的镜像。
二、镜像管理
常用选项:
$ docker image –help
OPTIONS DESCRIBE
ls/images 列出镜像
pull 从仓库拉取镜像到本地
push 从本地上传镜像到仓库
inspect 显示详情
history 镜像历史信息
import 导入tar归档的容器文件系统创建镜像
save 保存一个镜像到tar归档文件
load 从tar归档或标准输入导入镜像
rm 移除一个或多个镜像
build 从Dockerfile构建镜像
tag 创建一个引用源镜像标记目标镜像
Example:
从仓库拉取镜像
docker pull nginx:1.14
保存镜像到tar归档文件
$ docker image save nginx:1.14 > myweb.tar
从tar归档或标准输入导入镜像
$ docker image load < myweb.tar
引用源镜像标记目标镜像
$ docker image tag nginx:1.14 web:v1
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest 41a54fe1f79d 2 weeks ago 463MB
nginx 1.14 86898218889a 3 weeks ago 109MB
web v1 86898218889a 3 weeks ago 109MB
centos 7 5182e96772bf 7 weeks ago 200MB
centos latest 5182e96772bf 7 weeks ago 200MB
二、Dockerfile
官方仓库虽然有数十万的镜像资源,但在绝大多数情况下都不符合我们的需求,通常我们都会自己构建镜像。Dockfile 是一种被 Docker 程序解释的脚本, Dockerfile 由一条一条的指令组成,每条指令对应 Linux 下面的一条命令。Docker 程序将这些 Dockerfile 指令翻译真正的Linux命令。Docker 程序将读取 Dockerfile,根据指令生成定制的 image。
*注意:每一条指令就相当于给镜像加了一层,一个镜像不能超过 127 层,请惜字如金!
官方文档:https://docs.docker.com/engine/reference/builder/
常用指令:
OPTIONS DESCRIBE
FROM 基于哪个镜像构建新镜像
MAINTAINER(弃用) 镜像维护者信息
LABEL 同上,但用法更加灵活
RUN 构建镜像时运行的Shell命令
COPY 拷贝文件或目录到镜像中
CMD 运行容器时执行,如果有多个CMD指令,最后一个生效
ENTRYPOINT 运行容器时执行,如果有多个CMD指令,最后一个生效。可单独使用,也可与CMD配合使用
USER 为RUN、CMD、ENTRYPOINT执行指令指定运行用户
EXPOSE 声明容器运行的服务端口
WORKDIR 为RUN、CMD、ENTRYPOINT、COPY和ADD设置工作目录
VOLUME 指定挂载点,使容器中的一个目录具有持久化存储数据的功能
ENV 设置环境变量
ENTRYPOINT与CMD的区别在于ENTRYPOINT可以使用CMD作为参数,通常都是用作启动后台服务。
先来一个简单的 Dockerfile
创建一个工作目录,在工作目录下创建一个py脚本
FROM 指明以 centos:latest 作为基础镜像
COPY 指明复制源文件 test.py 到容器的 /tmp 目录下,test.py没指明路径,会运行 build 命令的当前目录下查找。
CMD 在容器启动时运行的命令
$ mkdir work
$ cd work/
$ cat test.py
#!/usr/bin/env python
print 'hello,container!'
$ cat Dockerfile
# Description: test image
FROM centos:latest
LABEL maintainer="Qukecheng "
COPY test.py /tmp
CMD python /tmp/test.py
docker build 命令是根据上下文自动构建镜像。构建上下文指定位置PATH或文件集URL,PATH是本地文件系统上的目录,URL是一个Git仓库地址。
构建由 Docker 守护程序运行,而不是CLI。构建过程第一件事是将整个上下文(递归)发送到守护进程。建议空目录作为上下文,并将 Dockerfile 保存在该目录下,目录中仅包含构建 Dockerfile 所需的文件,比如刚刚创建的 work 目录。
$ docker build –help
$ docker build -t myimage:v1 ./
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM centos:latest
—> 5182e96772bf
Step 2/4 : LABEL maintainer="Qukecheng "
—> Running in 804c23af5fb3
Removing intermediate container 804c23af5fb3
—> 2409cc31df3f
Step 3/4 : COPY test.py /tmp
—> 02f2546571b9
Step 4/4 : CMD python /tmp/test.py
—> Running in f3ce25242fca
Removing intermediate container f3ce25242fca
—> 72ff3d4714ca
Successfully built 72ff3d4714ca
Successfully tagged myimage:v1
使用刚刚生成的镜像,启动一个容器
$ docker container run –rm myimage:v1
hello,container!
还需要注意的是:
1. 一次 RUN 指令形成新的一层,进程让shell命令都写在一行,减少镜像层,一个镜像是不能超过 127 层的,在使用 RUN 指令时,可以在每条 shell 命令的结尾用转义换行 ""。
2. 一次 RUN 形成新的一层,如果没有在同一层删除,无论文件是否最后删除,都会带到下一层,所以要在每一层清理对应的残留数据,减少镜像大小。比如 yum 之后,清一下缓存。
三、构建部署Nginx
$ tree web/
web/
├── base
│ └── Dockerfile_nginx
└── project
├── Dockerfile_nginx
└── nginx.conf
$ mkdir -pv web/{base,project}
$ cd web/base/
$ touch Dockerfile_nginx
Nginx
$ cat Dockerfile_nginx
FROM centos:latest
LABEL maintainer="Qukecheng "
RUN yum install -y gcc gcc-c++ make
openssl-devel pcre-devel gd-devel libxslt-devel
iproute net-tools telnet wget curl &&
yum clean all &&
rm -rf /var/cache/yum/*
RUN wget http://nginx.org/download/nginx-1.14.0.tar.gz &&
tar -zxf nginx-1.14.0.tar.gz &&
cd nginx-1.14.0 &&
./configure –prefix=/usr/local/nginx
–with-http_ssl_module
–with-http_v2_module
–with-http_realip_module
–with-http_image_filter_module
–with-http_gunzip_module
–with-http_gzip_static_module
–with-http_secure_link_module
–with-http_stub_status_module
–with-stream
–with-stream_ssl_module &&
make -j $(grep processor /proc/cpuinfo | wc -l) && make install &&
cd / && rm -rf nginx-1.14.0*
ENV PATH $PATH:/usr/local/nginx/sbin
WORKDIR /usr/local/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
开始构建镜像
$ docker build -t nginx1.14 -f Dockerfile_nginx ./
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx1.14 latest 2b3cd8303924 10 minutes ago 323MB
centos latest 5182e96772bf 7 weeks ago 200MB
有了基础镜像,就可以基于这个镜像封装项目到镜像了
项目镜像
$ cd project/
$ touch Dockerfile_nginx nginx.conf
$ cat Dockerfile_nginx
FROM nginx1.14
COPY nginx.conf /usr/local/nginx/conf/
$ cat nginx.conf
user nobody;
worker_processes 1;
error_log logs/error.log info;
events {
worker_connections 4096;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr – $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
charset utf-8;
access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
}
}
$ docker build -t nginx:v1 -f Dockerfile_nginx ./
部署网站
$ docker network create web
$ docker volume create wwwroot
$ docker container run -d –name web_nginx -p 88:80 –network lnmp -v wwwroot:/usr/local/nginx/html nginx:v1
四、构建部署Java网站
Java 程序依赖于 JDK 环境,我们可以把 JDK 放在宿主机上,容器以挂载形式使用,减少镜像大小及提高性能。
$ tar -zxf jdk-8u91-linux-x64.tar.gz
$ sudo mv jdk1.8.0_91/ /usr/local/jdk1.8
$ tree java/
java/
├── apache-tomcat-8.5.16.tar.gz
└── Dockerfile
0 directories, 2 files
$ cd java/
$ cat Dockerfile
FROM centos:latest
LABEL maintainer="Qukecheng "
ENV VERSION=8.5.16
ENV JAVA_HOME=/usr/local/jdk
RUN yum install wget curl unzip iproute net-tools -y &&
yum clean all &&
rm -rf /var/cache/yum/*
COPY . /
RUN tar zxf apache-tomcat-${VERSION}.tar.gz &&
mv apache-tomcat-${VERSION} /usr/local/tomcat &&
rm -rf apache-tomcat-${VERSION}.tar.gz /usr/local/tomcat/webapps/* &&
mkdir /usr/local/tomcat/webapps/ROOT &&
echo '
Hello,Tomcat!
' > /usr/local/tomcat/webapps/ROOT/status.html &&
sed -i '1a JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"' /usr/local/tomcat/bin/catalina.sh &&
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ENV PATH $PATH:/usr/local/tomcat/bin
WORKDIR /usr/local/tomcat
EXPOSE 8080
CMD ["catalina.sh", "run"]
$ docker build -t tomcat8:latest ./
$ docker container run -d –name tomcat_srv -p 89:8080 -v /usr/local/jdk1.8/:/usr/local/jdk tomcat8:latest