转载过程中,图片丢失,代码显示错乱。
为了更好的学习内容,请访问原创版本:
https://www.missshi.cn/api/view/blog/5a6327d10a745f6335000005
Ps:初次访问由于js文件较大,请耐心等候(5s左右)
将Docker作为本地Web开发环境是Dockers的一个常见的应用场景。
这样可以保证开发运行与生产环境的配置、部署、依赖等一致,避免后续运维相关的问题。
下面,我们演示一下如何将Nginx安装到Docker中进行运行。
mkdir sample
cd sample
touch Dockerfile
下面,我们需要准备一些Nginx的配置的文件。
mkdir nginx && cd nginx
wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/global.conf
wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/nginx/nginx.conf
cd ..
接下来,我们修改Dockerfile
如下:
FROM ubuntu:14.04
MAINTAINER nianshi "[email protected]"
ENV REFREASHED_AT 2018-02-06
RUN apt-get update
RUN apt-get -y -q install nginx
RUN mkdir -p /var/www/html
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
其中,global.conf的内容如下:
server {
listen 0.0.0.0:80;
server_name _;
root /var/www/html/website;
index index.html index.htm;
access_log /var/log/nginx/default_access.log;
error_log /var/log/nginx/default_error.log;
}
另外,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;
}
其中,nginx配置为非守护进行的模型,从而可以在Docker中工作。
利用我们准备好的Dockerfile,可以使用docker build
命令来构建镜像。
docker build -t nianshi/nginx .
首先,执行如下命令来准备待测试的网站。
mkdir website && cd website
wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/website/index.html
cd ..
接下来,我们可以执行如下命令来启动容器:
sudo docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website nianshi/nginx nginx
此时,-v
参数进行卷映射。
卷的特点:
我们常常在如下场景中会使用卷:
Ps:在卷映射后,可以使用:ro
或者:rw
来指定读写权限。默认是可读写的。
执行上述命令后,我们可以使用docker ps
命令看查看当前运行的容器。
其Docker容器的80端口被映射到了本地的49161端口。
接下来,我们在浏览器中访问49161端口可以得到如下页面:
如果我们希望修改网站内容,那么我们可以直接编辑index.html
文件即可。
例如,我们将内容可以修改为
This is a test website for docker!
在上面的内容中,我们使用Docker运行了一个Nginx服务,可以用于测试一个静态网址。
接下来,我们将继续使用Docker来构建一个更大的Web应用程序。
编写Dockerfile文件如下:
FROM ubuntu:16.04
MAINTAINER nianshi "[email protected]"
ENV REFREASHED_AT 2018-02-07
RUN apt-get update
RUN apt-get -y install ruby2.3 ruby2.3-dev build-essential redis-tools
RUN gem install --no-rdoc --no-ri sinatra json redis
RUN mkdir -p opt/webapp
EXPOSE 4567
CMD [ "/opt/webapp/bin/webapp" ]
观察一下我们的Dockerfile文件,首先安装了Ruby和RubyGem工具。
接下来使用gem安装了sinatra json redis的Ruby库。
此外还创建了一个目录用于存放Web应用程序并公开了4567的端口。
最后指定了程序的启动命令。
下面,我们可以根据Dockerfile来构建镜像:
docker build -t nianshi/sinatra .
首先,我们需要下载应用程序依赖的源代码:
wget --cut-dirs=3 -nH -r --no-parent http://dockerbook.com/code/5/sinatra/webapp/
同时,我们需要将webapp/bin/webapp的文件修改为可执行文件。
chmod +x $PWD/webapp/bin/webapp
接下来,我们就可以启动Sinatra容器了:
sudo docker run -d -p 4567 --name webapp -v $PWD/webapp:/opt/webapp nianshi/sinatra
容器启动后,我们可以执行docker logs
命令来查看容器的日志信息:
docker logs -f webapp
此外,可以执行docker top
命令来查看容器的进程:
docker top webapp
下面,我们需要查看我们的容器的端口映射在本地宿主机的哪个端口,查看方式如下:
docker port webapp 4567
# 0.0.0.0:32768
上述结果表明该容器的4567端口映射到了本地宿主机的32768端口。
下面,我们来试用一下这个服务吧,该服务目前的功能非常简单,仅仅是将输入的数据转化为JSON的格式进行输出,示例如下:
接下来,我们将会拓展Sinatra应用程序,为其添加Redis数据库。
首先创建Dockerfile如下:
FROM ubuntu:16.04
MAINTAINER nianshi "[email protected]"
ENV REFREASHED_AT 2018-02-07
RUN apt-get -qq update && apt-get -qq install redis-server redis-tools
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server" ]
CMD []
我们在Dockerfile中指定了安装Redis服务器并公开了6379端口。
下面,我们来构造该镜像:
docker build -t nianshi/redis .
在镜像构造完成后,我们可以根据我们构建的镜像来启动容器:
docker run -d -p 6379 --name redis nianshi/redis
下面,我们需要检查一下redis映射到宿主机的哪个端口:
docker port redis 6379
# 0.0.0.0:32769
接下来,我们需要在本地尝试连接一下Redis服务器,从而检查Redis服务器是否能够正常工作。
首先检查一下本地是否安装有redis-cli
工具,如果没有的话需要执行如下命令进行安装:
apt-get install redis-tools
安装安装后,执行如下命令来连接Redis服务器:
redis-cli -h 127.0.0.1 -p 32769
# 127.0.0.1:32769>
如果进入了Redis交互式命令行,表示我们的Redis服务器目前是正常工作的。
为了将Sinatra服务能够连接到Redis数据库,我们需要能够在容器之间进行对话。
到目前为止,我们访问服务时都是通过将公开端口绑定到本地的宿主机的某个端口上,然后再来访问本地宿主机的端口。
除了这种方式之外,实际上每个Docker容器都有自己的IP地址。
通过容器自身的IP地址,我们也可以直接访问该容器的服务。
我们可以使用如下命令来直接查看容器的IP地址等信息:
docker inspect redis
# ...
# "NetworkSettings": {
# "Bridge": "",
# "EndpointID": "1fb2fe39f81332aeaade03549ee13046426d47f8528a46e074c6d8c9acee585c",
# "Gateway": "172.17.42.1",
# "GlobalIPv6Address": "",
# "GlobalIPv6PrefixLen": 0,
# "HairpinMode": false,
# "IPAddress": "172.17.0.18",
# "IPPrefixLen": 16,
# "IPv6Gateway": "",
#
其中,我们在NetworkSettings
中可以找到一个IPAddress
。
此处显示为172.17.0.18,即表明Redis容器的IP地址实际上就是172.17.0.18。
当然,由于inspect
命令是查看容器的全部信息,所以可能会存在大量我们并不太关心的内容,为了更加清晰的显示我们希望得到的信息,我们可以使用如下方式进行更细粒度的信息查询:
docker inspect -f '{{ .NetworkSettings.IPAddress }}' redis
# 172.17.0.18
我们可以直接使用该地址进行服务连接。此时,Redis的端口号不再是被映射的端口号32769了,而是默认的端口号6379。
连接一下试试吧:
redis-cli -h 172.17.0.18
# 172.17.0.18:6379>
那么我们是不是可以直接使用这种方式进行容器互联呢?实际上这种方式有一个致命的问题:那就是容器一旦重启,则该容器对应的IP地址会发生变化。
docker restart redis
docker inspect -f '{{ .NetworkSettings.IPAddress }}' redis
# 172.17.0.19
因此,如果我们在代码中对数据库的地址进行硬编码,则服务重启后就无法再正常运行了。
下面我们来了解一下如何在真正的应用中进行容器互联。
让容器之间可以相互连接主要借用了一个link的功能。
接下来,我们将关闭之前启动的全部容器,重新开始演示如何实现容器互联的功能。
Step1:启动Redis服务
docker run -d --name redis nianshi/redis
Ps:此处我们没有显示公开任何端口。后续会说明原因。
Step2:接下来,我们启动Web应用容器,并将其连接到新的Redis容器上。
docker run -p 4567 --name webapp --link redis:db -it -v $PWD/webapp:/opt/webapp nianshi/sinatra /bin/bash
在这个命令中,我们使用到了--link redis:db
。
link标识用于创建两个容器之间的连接,前者的参数表示的是容器名称,后者表示的是别名。
通过连接,可以让父容器有方法直接连接到子容器中。
Ps:在使用纯Docker时,被连接的容器必须在同一个Docker宿主机中。不同宿主机之间的容器如果想要连接,则需要借助Swarm或Kubernetes等编排工具。
在启动容器时,我们利用/bin/bash
进入和交互式命令环境,而不是直接启动服务。
主要原因是希望在容器中进一步了解容器直接是如何连接的。
Docker在父容器中的以下两个地方写入了连接信息:
我们先看一下/etc/hosts
文件:
cat /etc/hosts
# 172.17.0.21 8ec25c2f5c19
# ...
# 172.17.0.20 db 840a446245c4 redis
其中,第一部分是容器自己的IP地址和主机名称。
第二部分是有连接指令创建的,包含redis容器的IP地址和别名,主机名称以及容器名称。
此外,我们可以执行一下env
命令来查看一下相关的环境变量信息:
env
# HOSTNAME=8ec25c2f5c19
# DB_NAME=/webapp/db
# DB_PORT_6379_TCP_PORT=6379
# TERM=xterm
# DB_PORT=tcp://172.17.0.20:6379
# DB_PORT_6379_TCP=tcp://172.17.0.20:6379
# DB_ENV_REFRESHED_AT=2014-06-01
# DB_PORT_6379_TCP_ADDR=172.17.0.20
# DB_PORT_6379_TCP_PROTO=tcp
# SHLVL=1
# HOME=/root
# REFREASHED_AT=2018-02-07
# _=/usr/bin/env
这些环境变量中包含如下内容:
那么如何在我们的服务中利用这些环境变量提供的连接信息呢?
方式1: 使用环境变量
方式2:使用DNS和/etc/hosts信息
先看来第一种方法:利用环境变量。
在Web应用程序中lib/app.rb
文件中,可以如下获取host和port。
require 'uri'
...
uri = URI.parse(ENV['DB_PORT'])
redis = Redis.new(:host => uri.host, :port => uri.port)
...
此处,我们使用URI模块来解析DB_PORT环境变量,然后用于连接数据库,防止硬连接。
下面,我们来看另外一种方法:使用本地DNS。
使用方式如下:
redis = Redis.new(:host => 'db', :port => '6379')
此时,应用程序会在本地查找名为db的主机,通过/etc/hosts
文件解析得到正确的IP地址。
我们来启动该服务:
nohup /opt/webapp/bin/webapp &
服务启动后,我们来测试Redis服务是否正常。
Step1:用POST请求传递参数访问本地服务写入数据。
Step2:用GET请求查看目前存储的数据。
可以看到GET请求得到得到上次POST请求传送的数据,说明我们Redis服务已经正常启动了。
在这个相对完整的Web应用程序中,我们涉及到了如下内容:
以此为例,我们可以将其扩展到其他应用程序栈,例如Django,Flask等等。
更多更详细的内容,请访问原创网站:
https://www.missshi.cn/api/view/blog/5a6327d10a745f6335000005
Ps:初次访问由于js文件较大,请耐心等候(5s左右)