转载过程中,图片丢失,代码显示错乱。
为了更好的学习内容,请访问原创版本:
https://www.missshi.cn/api/view/blog/5a6328110a745f6335000006
Ps:初次访问由于js文件较大,请耐心等候(5s左右)
本文中我们将要构建的第一个应用是一个使用Jekyll框架的自定义网站。
该网站会包括以下两个镜像:
则以后开发过程可以转化如下:
首先,我们需要创建第一个Jekyll基础镜像。
我们需要创建一个新的目录并创建该镜像所需要的Dockerfile文件。
mkdir jekyll
cd jekyll
touch Dockerfile
修改Dockerfile
文件如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-17
RUN apt-get -qq update
RUN apt-get -qq install ruby ruby-dev build-essential nodejs libffi-dev
RUN gem install --no-rdoc --no-ri jekyll
VOLUME /data
VOLUME /var/www/html
WORKDIR /data
ENTRYPOINT [ "jekyll", "build", "--destination=/var/www/html" ]
在该Dockerfile
文件中,我们首先安装了Ruby和相关的包,此外,我们使用VOLUME
指令创建了两个卷:/data/
用于存放网站的源代码,/var/www/html
用于存放编译后的Jekyll文件。
创建好Dockerfile
文件后,我们可以执行如下命令来构建镜像:
docker build -t nianshi/jekyll .
命令执行完成后,我们则创建完成了一个jekyll的基础镜像。
接下来,我们需要继续创建一个新的文件夹用于构建Apache镜像。
mkdir apache
cd apache
touch Dockerfile
修改Dockerfile
文件如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
RUN apt-get -qq update
RUN apt-get -qq install apache2
VOLUME [ "/var/www/html" ]
WORKDIR /var/www/html
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid
ENV APACHE_RUN_DIR /var/run/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
RUN mkdir -p $APACHE_RUN_DIR $APACHE_LOCK_DIR $APACHE_LOG_DIR
EXPOSE 80
ENTRYPOINT [ "/usr/sbin/apache2" ]
CMD ["-D", "FOREGROUND"]
创建好Dockerfile
文件后,我们可以执行如下命令来构建镜像:
docker build -t nianshi/apache .
命令执行完成后,我们则创建完成了一个apache的基础镜像。
现在,我们已经完成了两个基础镜像的构建了。
下面,我们需要启动容器来构建我们的网站了:
首先需要下载网站所需要的源代码:http://www.missshi.cn/#/adminBook?_k=95xjmw
访问资源下载页面,搜索Jekyll示例服务依赖代码
下载并解压即可,此处我们假设解压目录是/home/nianshi/blog_demo
。
此时,我们可以执行如下命令来启动Jekyll容器:
docker run -v /home/nianshi/blog_demo:/data/ --name blog_demo nianshi/jekyll
此时,我们启动了一个blog_demo
的容器,并对卷进行了挂载,其中,本地的/home/nianshi/blog_demo
目录挂载到的容器中的/data/
文件夹下。另外容器对源代码编译后生成的代码会存放在/var/www/html/
卷下。
接下来,我们期望启动一个Apache容器,同时希望Apache容器可以连接到Jekyll容器中/var/www/html/
卷下获取编译后的文件。
我们可以执行如下命令:
docker run -d -P --name apache --volumes-from blog_demo nianshi/apache
在上述命令中,出现了一个新的参数--volumes-from
,该参数用于连接一个卷,从而可以访问到指定容器中的所有的卷。
Ps:当所有使用某个卷的容器全部都被rm
命令删除后,该卷会被自动释放。
下面我们来查看一下我们的容器映射到了机器的哪个端口吧:
docker port apache 80
# 0.0.0.0:32782
如果需要更新网站的数据,假设要修改Jekyll网站的博客名字,我们只需要通过编辑宿主机上james_blog/_config.yml
文件:并将title域改为Nianshi Blog。
然后通过使用docker start命令启动Docker容器即可。
可以看到,Jekyll编译过程第二次被运行,并且往网站已经被更新。这次更新已经写入了对应的卷。现在浏览Jekyll网站,就能看到变化了。
由于共享的卷会自动更新,这一切都不要更新或者重启Apache容器。这个流程非常简单,可以将其扩展到更复杂的部署环境。
如果担心一不小心删除卷。
由于卷的优点之一就是可以挂载到任意的容器,因此可以轻松备份它们。
现在创建一个新容器,用来备份/var/www/html
卷。
docker run --rm --volumes-from blog_demo -v $(pwd):/backup ubuntu tar cvf /backup/blog_demo_backup.tar /var/www/html
上述代码描述了一个最简单的备份方式,基于基础的ubuntu镜像,通过执行tar cvf
命令,将卷/var/www/html
中的内容压缩为blog_demo_backup.tar
文件,并存储到机器当前目录中。
接下来,我们考虑用Docker构建一个Java项目。
具体来说,主要分为两步:
首先创建一个新的目录用于准备构建WAR文件获取器镜像:
mkdir fetcher
cd fetcher
touch Dockerfile
接下来,修改Dockerfile
文件如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-18
RUN apt-get -qq update
RUN apt-get -qq install wget
VOLUME [ "/var/lib/tomcat7/webapps/" ]
WORKDIR /var/lib/tomcat7/webapps/
ENTRYPOINT [ "wget" ]
CMD [ "--help" ]
该镜像只完成一件非常简单的事,使用wget从指定的url中拉取文件并保存在/var/lib/tomcat7/webapps/
卷中。后续我们会将该卷共享到Tomcat服务器中。
下面,我们可以执行如下命令来构建镜像:
docker build -t nianshi/fetcher .
下面,我们以获取示例文件来启动我们刚才构建好的镜像:
docker run -it --name fetcher nianshi/fetcher https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war
# --2018-02-18 01:55:13-- https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war
# Resolving tomcat.apache.org (tomcat.apache.org)... 140.211.11.105, 195.154.151.36, 2001:bc8:2142:300::
# Connecting to tomcat.apache.org (tomcat.apache.org)|140.211.11.105|:443... connected.
# HTTP request sent, awaiting response... 200 OK
# Length: 4606 (4.5K)
# Saving to: 'sample.war'
#
# sample.war # 100%[===================================================================>] 4.50K --.-KB/s in 0s
#
# 2018-02-18 01:55:15 (217 MB/s) - 'sample.war' saved [4606/4606]
我们可以在Docker容器中切换到/var/lib/tomcat7/webapps/
目录下,我们可以找到刚刚下载得到的sample.war
文件。
同时,我们也可以在宿主机上找到该文件:
docker inspect -f "{{ .Mounts }}" fetcher
# [{642e56f6be0bb520661678cfa61f8c0182d3426a1b44092801bfcc20a154025f /mnt/docker_hub/volumes/642e56f6be0bb520661678cfa61f8c0182d3426a1b44092801bfcc20a154025f/_data /var/lib/tomcat7/webapps local true }]
该命令可以查询fetcher容器的Mounts所在的文件夹。其中,/mnt/docker_hub/volumes/642e56f6be0bb520661678cfa61f8c0182d3426a1b44092801bfcc20a154025f/_data
就是该卷在我们实际宿主机的位置。
下面,我们需要继续构建一个Tomcat7服务器镜像。
mkdir tomcat7
cd tomcat7
touch Dockerfile
修改Dockerfile
如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-18
RUN apt-get -qq update
RUN apt-get -qq install tomcat7 default-jdk
ENV CATALINA_HOME /usr/share/tomcat7
ENV CATALINA_BASE /var/lib/tomcat7
ENV CATALINA_PID /var/run/tomcat7.pid
ENV CATALINA_SH /usr/share/tomcat7/bin/catalina.sh
ENV CATALINA_TMPDIR /tmp/tomcat7-tomcat7-tmp
RUN mkdir -p $CATALINA_TMPDIR
VOLUME [ "/var/lib/tomcat7/webapps/" ]
EXPOSE 8080
ENTRYPOINT [ "/usr/share/tomcat7/bin/catalina.sh", "run" ]
下面,我们来构建一下该镜像:
docker build -t nianshi/tomcat7 .
下面,我们来启动Tomcat容器来运行一下示例应用吧:
docker run --name tomcat --volumes-from fetcher -d -P nianshi/tomcat7
该命令将会创建一个tomcat
容器,并关联fetcher
容器中共享的卷。
下面我们来查看一下映射在宿主机的端口
docker port tomcat 8080
# 0.0.0.0:32768
接下来,我们将分享一个使用Express框架的,带有Redis后端的Node.js的应用。
在本应用中,我们需要构建如下一系列镜像:
首先,同样是需要创建一个新的文件夹用于构建Node.js镜像。
mkdir nodejs
cd nodejs
mkdir -p nodeapp
touch Dockerfile
修改Dockerfile
文件如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-18
RUN apt-get -qq update
RUN apt-get -qq install nodejs npm
RUN ln -s /usr/bin/nodejs /usr/bin/node
RUN mkdir -p /var/log/nodeapp
ADD nodeapp /opt/nodeapp/
WORKDIR /opt/nodeapp
RUN npm install
VOLUME [ "/var/log/nodeapp" ]
EXPOSE 3000
ENTRYPOINT [ "nodejs", "server.js" ]
在该Dockerfile
文件中,我们使用ADD
命令将nodeapp
文件夹添加到了容器的/usr/bin/node
目录下。其中nodeapp
文件夹存储的是配置文件和实际代码。
Ps:代码可以访问http://www.missshi.cn/#/books?_k=xmjul9,搜索Node.js示例服务依赖代码
,下载并解压至nodeapp
文件夹即可。
其中,server.js
文件如下:
var fs = require('fs');
var express = require('express'),
app = express(),
redis = require('redis'),
RedisStore = require('connect-redis')(express),
server = require('http').createServer(app);
var logFile = fs.createWriteStream('/var/log/nodeapp/nodeapp.log', {flags: 'a'});
app.configure(function() {
app.use(express.logger({stream: logFile}));
app.use(express.cookieParser('keyboard-cat'));
app.use(express.session({
store: new RedisStore({
host: process.env.REDIS_HOST || 'redis_primary',
port: process.env.REDIS_PORT || 6379,
db: process.env.REDIS_DB || 0
}),
cookie: {
expires: false,
maxAge: 30 * 24 * 60 * 60 * 1000
}
}));
});
app.get('/', function(req, res) {
res.json({
status: "ok"
});
});
app.get('/hello/:name', function(req, res) {
res.json({
hello: req.params.name
});
});
var port = process.env.HTTP_PORT || 3000;
server.listen(port);
console.log('Listening on port ' + port);
下面,我们来构建容器
docker build -t nianshi/nodejs .
下面,我们需要继续构建Redis基础镜像。后续会根据该基础镜像来构建主从镜像。
mkdir redis_base
cd redis_base
touch Dockerfile
编写Dockerfile
文件如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-18
RUN apt-get -qq update
RUN apt-get install -qq software-properties-common python-software-properties
RUN add-apt-repository ppa:chris-lea/redis-server
RUN apt-get -qq update
RUN apt-get -qq install redis-server redis-tools
VOLUME [ "/var/lib/redis", "/var/log/redis" ]
EXPOSE 6379
CMD []
下面我们来构建Redis基础镜像:
docker build -t nianshi/redis_base .
接下来,我们基于Redis基础镜像来构建我们的Redis主镜像。
mkdir redis_primary
cd redis_primary
touch Dockerfile
编辑Dockerfile
文件如下:
FROM nianshi/redis_base
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2016-06-01
ENTRYPOINT [ "redis-server", "--protected-mode no", "--logfile /var/log/redis/redis-server.log" ]
构建该镜像:
docker build -t nianshi/redis_primary .
同样,我们来继续构建构建从镜像:
mkdir redis_slave
cd redis_slave
touch Dockerfile
编辑Dockerfile
文件如下:
FROM nianshi/redis_base
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-18
ENTRYPOINT [ "redis-server", "--protected-mode no", "--logfile /var/log/redis/redis-replica.log", "--slaveof redis_primary 6379" ]
构建该镜像:
docker build -t nianshi/redis_slave .
现在Redis的主从镜像都已经准备好了,我们来启动Redis后端集群。
首先启动主容器:
docker run -d -h redis_primary --name redis_primary nianshi/redis_primary
在该命令中,我们使用了-h
命令,-h
命令用于设置容器的主机名,从而保证本地DNS可以正确解析。
下面,我们来查看一下容器的日志吧,由于此处我们将容器日志定向到了指定的日志文件夹,而不是标准输出,因此我们不能通过之前的docker logs
命令来查看。
而是可以通过如下命令来查看日志:
docker run -it --rm --volumes-from redis_primary ubuntu cat /var/log/redis/redis-server.log
其中,我们启动了另外一个容器,该容器连接至Redis容器的卷用于查询日志,其中--rm
命令表示该容器运行结束后自动删除。
日志观察到我们的Redis服务已经正常启动了,下面我们可以继续创建Redis从服务了。
docker run -d -h redis_slave --name redis_slave --link redis_primary:redis_primary nianshi/redis_slave
其中,--link
参数用于将redis_primary
容器以别名redis_primary
连接到Redis从容器。
下面,我们来查看一下新容器的日志:
docker run -it --rm --volumes-from redis_slave ubuntu cat /var/log/redis/redis-replica.log
日志显示我们新启动的容器已经成功连接至Redis主容器。
下面,我们可以再启动第二个Redis从容器来提高服务的可靠性:
docker run -d -h redis_slave2 --name redis_slave2 --link redis_primary:redis_primary nianshi/redis_slave
目前,我们的后台Redis集群已经可以正常运行了,下面,我们可以启动Node容器了:
docker run -d --name nodeapp -p 4000:3000 --link redis_primary:redis_primary nianshi/nodejs
其中,-p 4000:3000
表示将容器的3000端口映射宿主机的4000端口。
此时,使用浏览器打开该页面即可:
输出为
{
"status": "ok"
}
表示服务目前正常工作,浏览器的会话状态被先记录到Redis的主容器后同步到了两个Redis从服务器上。
在生产环境中,我们需要确保可以捕获日志并保存到日志服务器中。
此处,我们以Logstash为例进行讲解,首先需要创建一个Logstash镜像:
mkdir logstash
cd logstash
touch Dockerfile
修改Dockerfile
如下:
FROM ubuntu:16.04
MAINTAINER nianshi <nianshi0912@gmail.com>
ENV REFRESHED_AT 2018-02-18
RUN apt-get -qq update
RUN apt-get -qq install wget
RUN wget -O - http://packages.elasticsearch.org/GPG-KEY-elasticsearch | apt-key add -
RUN echo 'deb http://packages.elasticsearch.org/logstash/1.5/debian stable main' > /etc/apt/sources.list.d/logstash.list
RUN apt-get -qq update
RUN apt-get -qq install logstash default-jdk
ADD logstash.conf /etc/
WORKDIR /opt/logstash
ENTRYPOINT [ "bin/logstash" ]
CMD [ "--config=/etc/logstash.conf" ]
此时,创建镜像的过程中用到了一个配置文件logstash.conf
,内容如下:
input {
file {
type => "syslog"
path => ["/var/log/nodeapp/nodeapp.log", "/var/log/redis/redis-server.log"]
}
}
output {
stdout {
codec => rubydebug
}
}
该配置文件表示logstash会监控两个文件:/var/log/nodeapp/nodeapp.log
和/var/log/redis/redis-server.log
,将其中新的内容发送给logstash。
下面,我们来构建logstash镜像:
docker build -t nianshi/logstash .
镜像构造完成后,我们可以执行如下命令来启动容器:
docker run -d --name logstash --volumes-from redis_primary --volumes-from nodeapp nianshi/logstash
容器启动后,我们可以执行如下命令来查看logstash容器的输出日志:
docker logs -f logstash
在之前的配置文件中,我们选择将日志进行标准输出,实际在生产环境中,我们更多的选择是会存储到Elasticsearch里。
传统上,我们管理机器的方式通常是通过SSH登入运行环境中来管理服务。
但是对于Docker而言,大部分容器内部仅仅只是运行一个进程,因此不推荐这种方式。
如果其中在Docker容器中执行某些命令,更推荐的方式如下:
docker exec [参数] 容器名称 [执行命令]
更多更详细的内容,请访问原创网站:
https://www.missshi.cn/api/view/blog/5a6328110a745f6335000006
Ps:初次访问由于js文件较大,请耐心等候(5s左右)