目錄
一、鏡像工作原理
二、鏡像管理
二、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