来源:The Docker Book读书笔记
[toc]
1 构建第一个应用
目标:构建一个应用使用Jekyll框架的自定义网址
会构建两个镜像:
Jektll镜像:一个镜像安装了Jekyll及其它用于构建Jekyll网站的必要安装包
Apache镜像:一个镜像通过Apache来让Jekyll网站工作起来
在启动容器时,通过构建一个新的Jekyll网站来进行实现自服务,公国流程如下:
- 创建Jekyll基础镜像和Apache基础镜像
- 从Jekyll基础镜像创建一个容器,这个容器存放通过卷挂载的网站源代码
- 从Apache基础镜像创建一个容器,这个容器共享包含编译后的网站的卷,为其服务
- 在网站需要更新的时候,清理并重复上面的步骤
1.1 构建Jekyll镜像
$mkdir jekyll
$cd jekyll
$vi Dockerfile
#####################start###########################
FROM ubuntu:16.04
MAINTAINER Boy
ENV REFRESHED_AT 2017-11-24
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update && apt-get install -y ruby ruby-dev build-essential nodejs
RUN gem install --no-rdoc --no-ri jekyll -v 2.5.3
#存在网站源代码
VOLUME /data
#存放编译后的Jekyll网站码
VOLUME /var/www/html
#设置工作目录
WORKDIR /data
#指定自动构建命令,将工作目录/data/中的Jekyll网站代码构建到/var/www/html目录中
ENTRYPOINT [ "jekyll", "build", "--destination=/var/www/html" ]
######################end##########################
$docker build -t boy/jekyll .
$docker images
1.2 构建Apache镜像
mkdir apache
cd apache
vi Dockerfile
######################start##########################
FROM ubuntu:16.04
MAINTAINER Boy
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update && apt-get -y install apache2
#创建卷,存放编译后的Jekyll网站
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
#在容器启动时运行apache
ENTRYPOINT [ "/usr/sbin/apache2" ]
CMD ["-D", "FOREGROUND"]
######################end##########################
$docker build -t boy/apache .
$docker images
1.3 创建Jekyll容器
将网站源码复制到宿主机中
$cd /home/james
$git clone https://github.com/jamtur01/james_blog.git
#这是一个最基础的Jekyll博客,可以在_config.yml中修改文件和主题
创建Jekyll容器
#容器名:james_blog,将宿主机/home/james/james_blog目录(源码)挂载到容器/data/卷
#容器拿到源码,并对其进行构建、编译
#存放在/var/www/html中(对应于Dockerfile文件的ENTRYPOINT命令)
$docker run -v /home/james/james_blog:/data --name james_blog boy/jekyll
1.4 创建Apache容器
#随机端口,volumes-from:将指定的james_blog容器中所有卷加入到新创建的容器中
#这意味着Apache容器可以访问之前创建的james_blog容器里/var/ww/html卷中存放的编译后的Jekyll网站
$docker run -d -P --volumes-from james_blog --name james_apache fpk/apache
1.5 宿主机浏览Jekyll网站
#查Apache端口
$docker port james_apache

1.6 更新Jekyll网站
#编辑Jekyll博客
$vi james_blog/_config.yml
$docker logs james_blog
查看更新后的网站!
1.7 备份Jekyll网站
卷的优点:可以挂载到任意的容器,轻松实现备份
现创建一个新的容器,用于备份/var/www/html卷
# --rm:用完即删,将james_blog容器中的卷挂载到此容器中
# tar cvf /backup/james_blog_backup.tar /var/www/html
# 将/var/www/html目录压缩到 /backup/james_blog_backup.tar中
$docker run --rm --volumes-from james_blog -v $(pwd):/backup ubuntu:16.04 tar cvf /backup/james_blog_backup.tar /var/www/html
#在$(pwd)中查看备份的tar包
2 使用Docker构建一个Java应用服务
把docker作为应用服务器和编译管道
目标:获取Tomcat服务器上的WAR文件,并运行一个Java应用程序
为此,构建一个有两个步骤的Docker管道
- 一个镜像从URL拉取指定的WAR包(源码)文件并将其保存到卷中
- 一个含有Tomcat服务器的镜像运行这些下载的WAR文件
2.1 构建含有WAR包的镜像
$mkidr fetcher
$cd fetcher
$ci Dockerfile
#############################start#############################
FROM ubuntu:16.04
MAINTAINER Boy
ENV REFRESHED_AT 2016-06-01
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update
RUN apt-get -y install wget
VOLUME [ "/var/lib/tomcat7/webapps/" ]
WORKDIR /var/lib/tomcat7/webapps/
ENTRYPOINT [ "wget" ]
CMD [ "--help" ]
#############################end#############################
$docker build -t jamtur01/fecher .
获取WAR包
#容器名:sample
$docker run -it --name sample jamtur01/fetcher https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war
#查看下载的卷
$docker inspect -f "{{range .Mounts}}{{.}}{{end}}" sample
$ll /var/lib/docker/volumes/c1cfb4d6545dec6514f4acb50e366ab12f60cea9db25cfce11b3233641dfa261/_data

2.2 构建Tomcat应用服务器镜像
$mkdir tomcat7
$cd tomcat7
$vi Dockerfile
#############################start#############################
FROM ubuntu:16.04
MAINTAINER Boy
ENV REFRESHED_AT 2016-06-01
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update
RUN apt-get -y 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
#启动Tomcat
ENTRYPOINT [ "/usr/share/tomcat7/bin/catalina.sh", "run" ]
#############################end#############################
$docker build -t jamtur01/tomcat .
2.3 创建Tomcat容器运行WAR文件
$docker run --name sample_app --volumes-from sample -d -P jamtur01/tomcat7
$docker port sample_app
Tomcat示例应用

2.4 基于Tomcat应用服务器的构建服务
安装ruby,ruby版本太低,需要升级
友情链接:
Ruby版本需要升级至2.2.2以上
RVM的安装和使用过程中碰到的问题
$yum -y install ruby
#使用RVM也就是Ruby Version Manager,Ruby版本管理器来升级ruby
#RVM包含了Ruby的版本管理和Gem库管理(gemset)。
#RVM安装
$curl -L get.rvm.io | bash -s stable
遇到了错误了,curl: (7) Failed connect to github-production-release-asset-2e65be.s3.amazonaws.com:443; Connection refused,不要怕,更换gem源:
友情链接:RubyGems 镜像
$gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
$gem sources -l
换了后,执行curl -L get.rvm.io | bash -s stable,有问题,不用管它,直接source /etc/profile.d/rvm.sh 就可以启用rvm,如果rvm成功安装的话,使用rvm -v就可以查看rvm的版本信息。
$source ~/.bashrc
$source ~/.bash_profile
#测试是否安装正常
$rvm -v
#列出已知ruby的版本
$rvm list known
#安装ruby 2.2.4
$rvm install 2.2.4
#安装ok后,ruby -v查看ruby的版本
$ruby -v
ruby的版本大于2.2.2后,安装TProv应用
$gem install --no-rdoc --no-ri tprov
#启动TProv
$tprov

填写Tomcat应用名和war包的url
Calendar
https://gwt-examples.googlecode.com/files/Calendar.war
出错了,原因:Network is unreachable..
要是成功的话提交查看
3 多容器的应用栈
最后一个服务应用示例:把一个使用Express框架的、带有Redis后端的Node.js应用完全Docker化
需要部署多个容器应用
- 一个Node容器,用于服务Node应用
- 一个Redis容器,用于保存和集群化应用状态
- 两个Reids副本容器,用于集群化应用状态
-
一个日志容器,用于捕获应用日志
image.png
3.1 构建Node.js镜像
源码地址:https://github.com/turnbullpress/dockerbook-code
$mkdir nodejs
$cd nodejs
$mkdir -p nodeapp
$wget https://github.com/turnbullpress/dockerbook-code/tree/master/code/6/node/nodejs/nodeapp/package.json
$wget https://github.com/turnbullpress/dockerbook-code/blob/master/code/6/node/nodejs/nodeapp/server.js
$cd ..
$vi Dockerfile
#########################start#########################
FROM ubuntu:16.04
MAINTAINER Boy
ENV REFRESHED_AT 2016-06-01
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update
RUN apt-get -y install nodejs npm
#符号连接,在/usr/bin目录下建立一个符号链接文件node,使它指向目录/usr/bin/nodejs
RUN ln -s /usr/bin/nodejs /usr/bin/node
RUN mkdir -p /var/log/nodeapp
#将宿主机的nodeapp源代码目录添加到/opt/nodeapp/
ADD nodeapp /opt/nodeapp/
WORKDIR /opt/nodeapp
RUN npm install
VOLUME [ "/var/log/nodeapp" ]
EXPOSE 3000
ENTRYPOINT [ "nodejs", "server.js" ]
#########################end#########################
#构建Node.jsjx
$docker build -t jamtur01/nodejs .
3.2 构建Redis基础镜像
$mkdir redis_base
$cd redis_base
$vi Dockerfile
#########################start#########################
FROM ubuntu:16.04
MAINTAINER Boy
ENV REFRESHED_AT 2017-06-01
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update
RUN apt-get install -y software-properties-common python-software-properties
RUN add-apt-repository ppa:chris-lea/redis-server
RUN apt-get -y update
RUN apt-get -y install redis-server redis-tools
VOLUME [ "/var/lib/redis", "/var/log/redis" ]
#公开默认端口6379
EXPOSE 6379
CMD []
#########################end#########################
$docker build -t jamtur01/redis .
3.3 构建Redis主镜像
$mkdir redis_primary
$cd redis_primary
$vi Dockerfile
#########################start#########################
FROM jamtur01/redis
MAINTAINER Boy
ENV REFRESHED_AT 2016-06-01
#指定启动Redis服务启动命令,保存其日志文件
ENTRYPOINT [ "redis-server", "--protected-mode no", "--logfile /var/log/redis/redis-server.log" ]
#########################end#########################
$docker build -t jamtur01/redis_primary .
3.4 构建Redis副本镜像
$mkdir redis_replica
$cd redis_replica
$vi Dockerfile
#########################start#########################
FROM jamtur01/redis
MAINTAINER Boy
ENV REFRESHED_AT 2016-06-01
#指定运行Redis的服务命令,设置日志文件和slavof选项(配置为主-副本模式)
#从这个镜像构建的任何容器都会将redis_primary主机的Redis作为主服务,连接其6379端口,成为其副本服务器
ENTRYPOINT [ "redis-server", "--protected-mode no", "--logfile /var/log/redis/redis-replica.log", "--slaveof redis_primary 6379" ]
#########################end#########################
$docker build -t jamtur01/redis_replica .
3.5 创建Redish后端集群
1 创建express网络
$docker network create express
2 运行Redis主容器
$docker run -d -h redis_primary --net express --name redis_primary jamtur01/redis_primary
使用docker logs redis_primary查看运行日志,没有,因为Redis服务会将日志记录到文件中,而不是记录到标准输出,为此使用之前创建的卷来读取日志文件
$docker run -it --rm --volumes-from redis_primary ubuntu:16.04 cat /var/log/redis/redis-server.log
哈哈哈,这种指定容器查看日志挂在卷的方法利用了卷的优势-共享,和容器的轻量化

3 运行Redis副本1容器
$docker run -d -h redis_replica1 --name redis_replica1 --net express jamtur01/redis_replica
查看日志
$docker run -it --rm --volumes-from redis_replica1 ubuntu:16.04 cat /var/log/redis/redis-replica.log

4 运行Redis副本2容器
$docker run -d -h redis_replica2 --name redis_replica2 --net express jamtur01/redis_replica
查看日志
$docker run -it --rm --volumes-from redis_replica2 ubuntu:16.04 cat /var/log/redis/redis-replica.log

至此,Redis后端集群设置完毕!
3.6 创建Node容器
$docker run -d --name nodeapp -p 3000:3000 --net express jamtur01/nodejs
$docker logs nodeapp

这个输出表明应用正常在工作,浏览器的会话状态会先被记录到Redis主容器redis_primary,然后被复制到redis_replica1和redis_replica2中
3.7 捕获应用日志
现在应用可以运行了,需要把这些应用放到生产环境中,在生产环境中需要确保可以捕获日志并将其保存到日志服务器中,此处使用Logstash来完成这件事,先创建Logstash镜像
需要安装jdk:
友情链接:http://blog.csdn.net/zhang__jiayu/article/details/43200685
$mkdir logstash
$cd logstash
$vi Dockerfile
#########################start#########################
FROM ubuntu:16.04
MAINTAINER Boy
ENV REFRESHED_AT 2016-06-01
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt-get clean
RUN apt-get -y update
RUN apt-get -y 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 -y install logstash
RUN apt-get -y install default-jdk
RUN update-alternatives --config java
RUN update-alternatives --config javac
#将logstash.conf添加到/etc/目录下
ADD logstash.conf /etc/
#指定工作目录
WORKDIR /opt/logstash
#容器启动时,启动Logstash,并加载/etc/logstash.cong配置文件,然后进行监视
ENTRYPOINT [ "bin/logstash" ]
CMD [ "--config=/etc/logstash.conf" ]
#########################end#########################
Logstash配置文件是logstash.cong,它监视两个文件,/var/log/nodeapp/nodeapp.log(nodeapp) 和 /var/log/redis/redis-server.log (之前指定的日志目录),Logstash会一直监视这两个文件,将其中新的内容发送给Logstash,配置文件第二部分的output部分是:接受所有Logstash输入的内容,并将其输出到标准输出上。
构建Logstash镜像
$docker build -t jamtur01/logstash .
启动Logstash容器
$docker run -d --name logstash --volumes-from redis_primary --volumes-from nodeapp jamtur01/logstash
查看logstash容器的日志
$docker logs -f logstash
现在再在浏览器中刷新web应用,产生一个新的日志事件,这样能在logstash容器中输出中看到这个事件

现在Node和Redis容器都将日志输出到Logstash。在生产环境中,这些事件会发到Logstash服务器并存储在Elasticsearch里。如果要加入新的Redis副本容器或其他的组建,也很容易地将其日志输出到日志容器中。
