介绍完Docker 容器、镜像与仓库、构建镜像等基础知识后,接下来几篇将介绍一些Docker 使用示例。本篇我们将基于Dockerfile文件构建一个Nginx静态网站服务器,并使用这个服务器运行一个存在于宿主机上的静态网站,并基于Docker容器卷实现对这个网站的实时更新。
在本文中,我们会使用Nginx Web服务器来搭建一个简单的网站服务器,网站命令为petweb。
1. Dockerfile及初始化
首先,创建一个目录,并在其中创建Dockerfile文件。
$ mkdir petweb $ cd petweb $ touch Dockerfile
1.1 创建Nginx配置文件
我们会使用Nginx做为Web服务器,用于运行网站,要运行网站还需要一些配置文件。在示例目录中创建一个nginx目录,用于保存这些配置文件:
$ mkdir nginx cd nginx
创建Nginx全局配置nginx.conf及站点配置文件petweb.conf:
$ touch nginx.conf $ vi nginx.conf
nginx.conf文件内容如下:
user www-data;
worker_processes 4;
pid /run/nginx.pid;
daemon off;
events { }
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
}
在这个配置方中,我们通过daemon off指定Nginx以非守护进程的模式运行(前台运行),这样就可以使Nginx在容器内保持运行。
注意:Nginx默认是以守护进程的模式运行的,在这种模式下,守护进程被fork启动后,启动守护进程的原始进程就会退出,Docker 容器也会随之停止。因此,需要通过前台运行的方式使容器保持运行。
$ touch petweb.conf $ vi petweb.conf
petweb.conf文件内容如下:
server {
listen 0.0.0.0:80;
server_name _;
root /var/www/html/petweb;
index index.html index.htm;
access_log /var/log/nginx/default_access.log;
error_log /var/log/nginx/default_error.log;
}
在这个文件中,我们指定了Nignx监听80端口,并指定网站在服务器目录/var/www/html/petweb。
1.2 初始化Dockerfile
接下来编辑petweb网的Dockerfile:
$ cd .. $ vi Dockerfile
Dockerfile文件内容如下:
FROM ubuntu:16.04 LABEL creater="IT笔录" description="这是一个静态网站" version="1.0" ENV REFRESHED_AT 2017-02-26 RUN apt-get -yqq update && apt-get install -yqq nginx RUN mkdir -p /var/www/html/petweb ADD nginx/petweb.conf /etc/nginx/conf.d/ ADD nginx/nginx.conf /etc/nginx/nginx.conf EXPOSE 80
在这个Dockerfile文件中,包含了以下内容:
- 安装Nginx
- 通过
LABEL添加了一些镜像描述 - 在容器内创建
/var/www/html/petweb。注意这个目录也是我们petweb.conf文件中所配置的站点根目录 - 然后通过
ADD命令将本地配置文件添加到了镜像中 - 最后公开了容器的
80端口
2. 构建镜像及网站
2.1 构建镜像
使用刚创建的Dockerfile文件,通过docker build构建新镜像,并将镜像命名为itbilu/nginx:
$ sudo docker build -t itbilu/nginx .
命令执行完成后,会生成一个新镜像。可以通过docker history查看镜像的分层关系及构建过程:
$ sudo docker history itbilu/nginx IMAGE CREATED CREATED BY SIZE COMMENT fcdae3cd7037 About an hour ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B 657e30fcad6b About an hour ago /bin/sh -c #(nop) ADD file:df60f3554177125... 414 B 9a4a73d7965e About an hour ago /bin/sh -c #(nop) ADD file:0b0356863b20464... 249 B 6ab912797ab9 About an hour ago /bin/sh -c mkdir -p /var/www/html/petweb 0 B 91776884e69c About an hour ago /bin/sh -c apt-get -yqq update && apt-get ... 96.7 MB 638db5680761 About an hour ago /bin/sh -c #(nop) ENV REFRESHED_AT=2017-0... 0 B 57aa9a5a8bda About an hour ago /bin/sh -c #(nop) LABEL creater=IT笔录 desc... 0 B f49eec89601e 5 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B <missing> 5 weeks ago /bin/sh -c mkdir -p /run/systemd && echo '... 7 B <missing> 5 weeks ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\... 1.9 kB <missing> 5 weeks ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0 B <missing> 5 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' >... 745 B <missing> 5 weeks ago /bin/sh -c #(nop) ADD file:68f83d996c38a09... 129 MB
2.2 创建petweb网站
镜像构建完成后,就可以通过新创建的镜像运行网站容器,运行前我们先创建静态网站站。
创建网站目录website,并其中创建网站的HTML文件。
$ mkdir website $ cd website $ touch index.html $ vi index.html
网站建设不在本文的介绍范围,在本例中只创建一个网站文件index.html,用于演示基于Docker进行站点管理和更新过程。文件内容如下:
<!DOCTYPE html> <html> <head> <title>PetWeb</title> </head> <body> <h1>这是一个名叫<em>PetWeb</em>的静态网站</h1> <p>虽然网站只有一个文件,但能够演示基于Docker进行站点管理和更新过程。</p> <p>来自:<a href="https://niefengjun.cn" target="_blank">IT笔录</a></p> </body> </html>
编辑完成后,返回上层目录:
$ cd ..
3. 运行容器
接下来,使用新构建的镜像来运行一个容器,运行容器时将刚创建的静态网站挂载到容器中:
$ sudo docker run -d -p 80 --name petweb \ -v $PWD/website:/var/www/html/petweb \ itbilu/nginx nginx
在这个命令中,我们使用itbilu/nginx容器创建并运行了一个容器,容器名为petweb。创建容器时,通过-v参数将宿主机的$PWD/website目录做为卷挂载到了容器的/var/www/html/petweb。而/var/www/html/petweb目录就是在创建镜像,通过petweb.conf配置文件指定的站点在容器内的工作目录。
关于卷:卷是被一个或多个容器内所使用的目录,卷可以绕过联合文件系统,对卷内数据的修改会即时生效。且创建和修改镜像时,卷是不被包含到镜像中的。因此,卷非常适用于存放频繁改动、而又不必提交到镜像中的数据,或需要在多个容器间共享的数据等。更多关于卷的介绍请参考:
为容器添卷时,还可以通过rw或ro参数指定容器内目录的读写状态。如,设置为只读状态:
$ sudo docker run -d -p 80 --name petweb \ -v $PWD/website:/var/www/html/petweb:ro \ itbilu/nginx nginx
运行容器后,可以通过docker ps命令看到运行中的容器:
$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 73a4dcd7ba7b itbilu/nginx "nginx" 3 hours ago Up 3 hours 0.0.0.0:32771->80/tcp petweb
如上所示,由于运行容器时我们没指定本机端口,因此随机分配了一个32771端口映射到了容器的80端口。这时,可以浏览器输入localhost:32771或127.0.0.1:32771来查看网站的运行状态:

4. 网站修改
经过上面的步骤我们已经成功运行了一个静态网站。由于业务发展,我们需要修改这个静态站,这时该怎么办呢?
在前面运行容器时,我们通过-v参数,以卷的方式将本地目录挂载到了容器内。要修改站点时,只需要在本地目录修改即可。
如,在本目录将index.html修改为如下内容:
<!DOCTYPE html> <html> <head> <title>PetWeb</title> </head> <body> <h1>这是一个用Docker运行的,名叫<em>PetWeb</em>的静态网站</h1> <p>虽然网站只有一个文件,但能够演示基于Docker进行站点管理和更新过程。</p> <p>来自:<a href="https://niefengjun.cn" target="_blank">IT笔录</a></p> </body> </html>
现在刷新浏览器,看到效果如下:

可以看到,修改已经成功了。利用卷的这一特征,我们可以非常简单的修改容器外部或容器间共享的数据。
在实际生产环境中也是如此,在生产环境中,我们可为服务器(如:Nginx、Apache)配置一个容器、给不同的开发框架配置一个容器(如:Node.js、PHP)、给数据库配置一个容器,等等。再通过卷在容器间或容器与宿主机之间实现数据的共享,从而实现应用的模块化布暑。
