Docker学习笔记六 使用Docker构建服务

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

6.1 使用Jekyll框架和Apache构建应用

需要构建两个镜像:

  • 一个镜像安装了Jekyll以及其他用于构建Jekyll网站的必要的软件包;
  • 一个镜像通过Apache来让Jekyll网站工作起来。

工作流程如下:

  1. 创建Jekyll基础镜像和Apache镜像;
  2. 从Jekyll镜像创建一个容器,这个容器存放通过卷挂载的网站源代码;
  3. 从Apache镜像创建一个容器,这个容器利用包含编译后的网站的卷为其创建服务;
  4. 在网站需要更新时,清理并重复上面的步骤。

这个例子可以看做是创建一个多主机站点最简单的方法。

1、Jekyll基础镜像

建立构建环境:

mkdir jekyll
cd jekyll
touch Dockerfile

编写Dockerfile:

FROM ubuntu:14.04
MAINTAINER James Turnbull 

RUN apt-get -yqq update
RUN apt-get -yqq install ruby ruby-dev make nodejs
RUN gem install --no-rdoc --no-ri jekyll -v 2.5.3

VOLUME /data
VOLUME /var/www/html
WORKDIR /data

ENTRYPOINT [ "jekyll", "build", "--destination=/var/www/html" ]

注意书上的代码 gem jekyll 后面没有 -v 2.5.3,会报错。

在Dockerfile中使用VOLUME指令创建了两个卷:

  • /data/,用于存放网站源代码;
  • /var/www/html/,用于存放编译后的Jekyll网站码。

最后,将工作目录指定为/data,并通过ENTRYPOINT指令指定自动构建的命令,这个命令将工作目录/data/中所有的Jekyll网站代码构建到/var/www/html/目录中。

2、构建Jekyll基础镜像

docker build -t ivan/jekyll .

3、Apache镜像

建立构建环境:

mkdir apache
cd apache
touch Dockerfile

编写Dockerfile:

FROM ubuntu:14.04
MAINTAINER James Turnbull 

RUN apt-get -yqq update
RUN apt-get -yqq 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"]

使用了VOLUME指令创建了一个卷——/var/www/html/,这个目录是用来存放编译后的jekyll网站的;

最后指定了ENTRYPOINT和CMD指令组合来在容器启动时默认运行apache。

4、构建Apache镜像

docker build -t ivan/apache .

5、启动Jekyll网站

首先将Jekyll的一些源代码下载:

cd ~
git clone https://github.com/jamtur01/james_blog.git

然后启动容器:

docker run -v ~/james_blog:/data/ --name james_blog ivan/jekyll

把刚才从github上下载的james_blog目录作为卷挂载到/data(目录里有jekyll网站的源码)。

这里再复习一下卷,卷是在一个或多个容器中特殊指定的目录,卷会绕过联合文件系统,为持久化数据和共享数据提供几个有用的特性:

  • 卷可以在容器间共享和共用;
  • 共享卷时不一定要运行相应的容器;
  • 对卷的修改会直接在卷上反映出来;
  • 更新镜像时不会包含对卷的修改;
  • 卷会一直存在,直到没有容器使用它们。

卷在Docker宿主机的/var/lib/docker/volumes目录中,通过docker inspect命令可以查看某个卷的具体位置:

docker inspect -f "{{.Volumes}}"

如果想在另一个容器里使用/var/www/html/卷里编译好的网站,可以创建一个新的容器连接到这个卷(即Apache容器):

docker run -d -P --volumes-from james_blog ivan/apache

--volumes-from标志把指定容器里所有的卷加入新建的容器里。

如果删除了最后一个使用卷的容器,卷就被删除了。所以删除有卷的容器时要小心。

这样整个服务就启动好了。

6、备份Jekyll卷

上文说道删除容器可能不小心将卷删除了。所以可以利用一下命令备份卷:

docker run --rm --volumes-from james_blog -v $(pwd):/backup ubuntu tar cvf /backup/james_blog_backup.tar /var/www/html

--rm命令表示该容器只使用一次,运行完后就删除。

将当前目录挂载到/backup,这样在容器中将数据打包到/backup后,该包其实就在当前目录下。

tar cvf命令会创建一个名为james_blog_backup.tar的tar文件(该文件包含了/var/www/html目录里的所有内容)。

7、扩展Jekyll示例

  • 运行多个Apache容器,这些容器都使用james_blog容器的卷,在这些Apache容器前面加一个负载均衡器,就拥有了Web集群;
  • 进一步构建一个镜像,这个镜像把用户提供的源数据复制到卷里,再把这个卷挂载到jekyll容器里。这就是一个可迁移的通用方案,而且宿主机本地包含任何源代码;
  • 在上一个扩展基础上为我们的服务构建一个Web前段,这个服务用语从指定的源自动构建和部署网站。

6.2 构建一个Java应用服务(Tomcat)

1、WAR文件获取器

创建构建环境

mkdir fetcher
cd fetcher
touch Dockerfile

编写Dockerfile

FROM ubuntu:14.04
MAINTAINER Ivan Jiang 
ENV REFRESHED_AT 2016-07-13
 
RUN apt-get -yqq update
RUN apt-get -yqq install wget
 
VOLUME ["/var/lib/tomcat7/webapps/"]
WORKDIR /var/lib/tomcat7/webapps/
 
ENTRYPOINT ["wget"]
CMD ["--help"]

容器执行时,使用wget从指定的URL获取文件,并把它保存在/var/lib/tomcat7/webapps目录。如果运行容器时没有指定URL,ENTRYPOINT和CMD指令组合起来返回wget的帮助。

2、获取WAR文件

docke run -t -i --name sample ivan/fetcher https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war

3、构建Tomcat7应用服务器

创建构建环境:

mkdir tomcat7
cd tomcat7
touch Dockerfile

编写Dockerfile:

FROM ubuntu:14.04
MAINTAINER Ivan Jiang 
ENV REFRESHED_AT 2016-07-13
 
RUN apt-get -yqq update
RUN apt-get -yqq 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 ivan/tomcat7 .

4、运行tomcat7容器

docker run --name sample_app --volumes-from sample -d -P ivan/tomcat7

查看映射到宿主机的端口号:

docker port sample_app 8080

假设端口号是49154,在浏览器访问:IP地址:49154/sample可查看运行的web app。

在例子中作者使用了命令:

docker inspect -f "{{.Volumes}}" sample

查看sample卷的宿主机挂载位置,但是这个命令报错。

OSChina上的TimWang回答我的问题说Docker 1.8将Volumes信息从docker inspect 的输出中删除了,需改用Mounts:

docker inspect -f "{{.Mounts}}" sample

6.3 多容器的应用栈

1、Node.js镜像

创建构建环境:

mkdir nodejs
cd nodejs
touch Dockerfile

编写Dockerfile:

FROM ubuntu:14.04
MAINTAINER James Turnbull 
ENV REFRESHED_AT 2014-06-01

RUN apt-get -yqq update
RUN apt-get -yqq 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" ]

用ln -s建立软连接,把二进制文件modejs连接到node,解决Ubuntu上原有的一些无法向后兼容问题(不懂……)。

构建镜像:

docker build -t ivan/nodejs .

2、Redis基础镜像

mkdir redis_base
cd redis_base
touch Dockerfile
FROM ubuntu:14.04
MAINTAINER James Turnbull 
ENV REFRESHED_AT 2014-06-01

RUN apt-get -yqq update
RUN apt-get install -yqq software-properties-common python-software-properties
RUN add-apt-repository ppa:chris-lea/redis-server
RUN apt-get -yqq update
RUN apt-get -yqq install redis-server redis-tools

VOLUME [ "/var/lib/redis", "/var/log/redis" ]

EXPOSE 6379

CMD []
docker build -t ivan/redis .

3、Redis主镜像

mkdir redis_primary
cd redis_primary
touch Dockerfile
FROM ivan/redis
MAINTAINER James Turnbull 
ENV REFRESHED_AT 2014-06-01

ENTRYPOINT [ "redis-server", "--logfile /var/log/redis/redis-server.log" ]
docker build -t ivan/redis_primary

4、Redis从镜像

mkdir redis_replica
cd redis_replica
touch Dockerfile
FROM ivan/redis
MAINTAINER James Turnbull 
ENV REFRESHED_AT 2014-06-01

ENTRYPOINT [ "redis-server", "--logfile /var/log/redis/redis-replica.log", "--slaveof redis_primary 6379" ]
docker build -t ivan/redis_replica .

5、创建Redis集群

启动Redis主镜像

docker run -d -h redis-primary --name redis_primary ivan/redis_primary

这里使用-h参数指定容器的主机名,书中给出的是redis_primary,但是执行会报错,应该是新版本的Docker不支持带下划线的主机名,这里改为redis-primary。

启动Redis从服务

docker run -d -h redis-replical --name redis_replical --link redis_primary:redis_primary ivan/redis_replica

这里对-h参数做相同的处理。

6、创建Node容器

docker run -d --name nodeapp -p 3000:3000 --link redis_primary:redis_primary ivan/nodejs

在浏览器中用 宿主机IP:3000测试。

7、捕获应用日志

使用Logstash捕获日志并将日志保存到日志服务器。

mkdir logstash
cd logstash
touch Dockerfile
FROM ubuntu:14.04
MAINTAINER James Turnbull 
ENV REFRESHED_AT 2014-06-01

RUN apt-get -yqq update
RUN apt-get -yqq install wget
RUN wget -O - http://packages.elasticsearch.org/GPG-KEY-elasticsearch |  apt-key add -
RUN echo 'deb http://packages.elasticsearch.org/logstash/1.4/debian stable main' > /etc/apt/sources.list.d/logstash.list
RUN apt-get -yqq update
RUN apt-get -yqq install logstash

ADD logstash.conf /etc/

WORKDIR /opt/logstash

ENTRYPOINT [ "bin/logstash" ]
CMD [ "--config=/etc/logstash.conf" ]

Logstash监控两个文件/var/log/nodeapp/nodeapp.log和/var/log/redis/redis-server.log,将其中的新内容捕获,捕获到的内容输出到标准输出上。现实中一般会将Logstash的内容输出到Elasticsearch集群。

构建之前将作者的logstash.conf下载到构建根目录。

构建镜像

docker build -t ivan/logstash .

启动容器

docker run -d --name logstash --volumes-from redis_primary --volumes-from nodeapp ivan/logstash

查看logstash容器的输出日志

docker logs -f logstash

6.4 不使用SSH管理Docker容器

传统上,使用SSH登入运行环境或者虚拟机管理服务。在Docker里,大部分容器只运行一个进程,所以不能使用这种方法。可是使用卷或者链接完成大部分管理操作。如需要给容器发送信号,可以使用docker kill命令:

docker kill -s  

这个操作会发送指定的信号给容器,而不是杀掉容器。

可以使用nsenter小工作登入容器,它一般适用于1.2或更早的版本,1.3版本引入的docker exec替换了它大部分的功能。

工具nsenter可以进入Docker用来构成容器的内核命名空间。它可以进入一个已经存在的命名空间,或者在新的一组命名空间里执行一个进程。

可以通过Docker容器安装nsenter:

docker run -v /usr/local/bin:/target jpetazzo/nsenter

这会把nsenter安装到/usr/local/bin目录下。

为了使用nsenter,首先要知道要进入的容器的进程ID,可以使用docker inspect命令获得进程PID:

PID=$(docker inspect --format {{.State.Pid}} )

然后运行下面的命令进入容器:

nsenter --target $PID --mount --uts --ipc --net --pid

也可以将容器内执行的命令添加在nsenter命令行的后面:

nsenter --target $PID --mount --uts --ipc --net --pid ls

转载于:https://my.oschina.net/u/2453016/blog/711216

你可能感兴趣的:(Docker学习笔记六 使用Docker构建服务)