5.1 使用Docker测试静态网站(Nginx)html
将项目命名为Samplenginx
首先创建构建环境git
mkdir sample cd sample touch Dockerfile
在构建环境中下载做者配置好的两个nginx配置文件:github
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
写Dockerfileweb
FROM ubuntu:14.04 MAINTAINER Ivan Jiangzhi "ivanjz93@163.com" ENV REFRESHED_AT 2016-07-09 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
在nginx.conf配置文件中daemon off;选项阻止Nginx进入后台,强制其在前台运行。这是由于想要保持Docker容器的活跃状态,须要其中运行的进程不能中断。默认状况下,Nginx会以守护进程的方式启动,这会致使容器只是短暂运行,在守护进程被fork启动后,发起守护进程的原始进程就会退出,这时容器就中止了。redis
构建Sampledocker
docker build -t ivan/nginx .
构建完成后可以使用docker history查看构建步骤:json
docker history ivan/nginx
下载做者写好的html(或者本身写一个也能够)ubuntu
mkdir website && cd website wget https://raw.githubusercontent.com/jamtur01/dockerbook-code/master/code/5/sample/website/index.html
建立容器并运行浏览器
docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website ivan/nginx nginx
-v 选项将宿主机的目录做为卷挂载到容器里。
卷是在一个或者多个容器内被选定的目录,能够绕过度层的联合文件系统,为Docker提供持久数据或者共享数据。这意味着对卷的修改会直接生效并绕过镜像。当提交或者建立镜像时,卷不被包含在镜像里。
在下面的时候能够考虑使用卷:
-v 指定了卷的源目录(宿主机目录)和容器里的目录,这两个目录用:分割。若是目的目录不存在,Docker会自动建立一个。
也能够经过在目的目录后面加上rw或者ro来指定目的目录的读写状态:
docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website:ro ivan/nginx nginx
上例使目的目录变成只读状态。
docker run成功后在浏览器中访问 宿主机IP:映射端口便可看到页面,修改$PWD/website/index.html保存后刷新浏览器即时生效。
5.2 构建并测试Web应用程序(Sinatra + Redis)
一、构建Sinatra应用程序
建立sinatra构建环境:
mkdir sinatra cd sinatra touch Dockerfile
编写Dockerfile,书上的例子:
FROM ubuntu:14.04 MAINTAINER James Turnbull james@example.com ENV REFRESHED_AT 2014-6-1 RUN apt-get update RUN apt-get -y install ruby ruby-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"]
构建镜像
docker build -t ivan/sinatra .
二、建立Sinatra容器
下载做者编写的Sinatra Web应用程序的源码:
wget --cut-dirs=3 -nH --no-parent --no-check-certificate http://dockerbook.com/code/5/sinatra/webapp/
使用书中的命令下载时会报错,按报错的提示加入--no-check-certificate参数后成功下载。
为webapp/bin/webapp添加执行权限:
chmod +x $PWD/webapp/bin/webapp
启动容器并把$PWD/webapp按卷挂在到容器中:
docker run -d -p 4567 --name webapp -v $PWD/webapp:/opt/webapp ivan/sinatra
我在操做时遇到的问题和解决方法
构建时会报错,说安装的ruby是1.9版本,而gem install json须要2.0以上的版本。
我直接从ruby镜像构建,去掉apt-get ruby的安装,容器能够正常构建。可是启动时会包找不到/opt/webapp/bin/webapp的错误,执行的权限已经添加,/bin/bash命令启动容器发现webapp用/usr/bin/ruby启动,可是容器里的ruby在/usr/local/bin/ruby,因此在构建时添加cp命令。个人Dockerfile以下:
FROM ruby MAINTAINER James Turnbull james@example.com ENV REFRESHED_AT 2014-6-1 RUN apt-get update RUN apt-get -y install ruby-dev build-essential redis-tools RUN gem install --no-rdoc --no-ri sinatra json redis RUN mkdir -p /opt/webapp RUN cp /usr/local/bin/ruby /usr/bin/ruby EXPOSE 4567 CMD ["/opt/webapp/bin/webapp"]
启动成功后查看执行命令的输出:
docker logs webapp
查看容器运行的进程:
docker top webapp
查看容器的4567端口映射到宿主机的端口:
docker port webapp 4567
测试Sinatra应用的运行状况,假设映射到宿主机的端口为49160(它接收输入参数,并将其转化为Json返回):
curl -l -H 'Accept:application/json' -d 'name=Foo&status=Bar' http://localhost:49160/json
三、构建Redis镜像和容器
建立redis构建环境:
mkdir redis cd redis touch Dockerfile
redis Dockerfile的内容:
FROM ubuntu:14.04 MAINTAINER James Turnbull james@example.com ENV REFRESHED_AT 2016-07-11 RUN apt-get update RUN apt-get -y install redis-server redis-tools EXPOSE 6379 ENTRYPOINT ["/user/bin/redis-server"] CMD []
构建redis镜像:
docker build -t ivan/redis .
建立并启动redis容器:
docker run -d -p 6379 --name redis ivan/redis
查看容器 6379端口映射到宿主机上的哪一个端口:
docker port redis 6379
而后在宿主机上使用redis-cli测试redis-server在容器中的运行状况:
sudo apt-get -y install redis-tools redis-cli -h 127.0.0.1 -p 49161
(假设容器的6379端口映射到了宿主机的49161端口上)。
我在宿主机的ubuntu上使用apt-get -y install redis-tools报没法定位redis-tools packages的错误,直接apt-get -y install redis-server 后可使用redis-cli。
四、链接到Redis容器
通常有两种方法实现容器间的网络链接:
第一,Docker容器公开端口并绑定到本地网络接口,这样能够把容器里的服务在本地Docker宿主机所在的外部网络上公开(好比,把容器里的80端口绑到本地宿主机的高端口上)。
第二,内部网路。在安装Docker时,会建立一个新的网络接口,名字是docker0。docker0接口有符合RFC1918的私有IP地址,范围是172.16~172.30。docker0接口自己的地址是这个Docker网络的网关地址,也是全部Docker容器的网关地址。Docker默认会使用172.17.x.x做为子网地址,若是这个子网被占用,会在172.16~172.30这个范围内尝试建立子网。接口docker0是一个虚拟的以太网桥,用于链接容器和本地宿主网络。Docker宿主机的会有一系列名字以veth开头的接口,Docker每建立一个容器就会建立一组互联的网络接口。这组接口就像管道的两端,其中一端做为容器里的eth0接口,而另外一端统一命名为以veth开头的名字,做为宿主机的一个端口。经过把每一个veth*接口绑定到docker0网桥,Docker建立了一个虚拟子网,这个子网由宿主机和全部的Docker容器共享。
在运行的容器内部查看一下对望通讯的路由信息,发现容器地址后的下一跳就是宿主网络上docker0的地址:
apt-get -yqq update && apt-get install -yqq traceroute traceroute google.com
(3)Docker网络还有另一个部分的配置才能容许创建链接:防火墙规则和NAT配置。这些配置容许Docker在宿主网络和容器间路由。在宿主机上查看IPTables NAT配置:
sudo iptables -t nat -L -n
容器默认是没法访问的。从宿主网络与容器通讯时,必须明确指定打开的端口。
五、链接Redis
用docker inspect查看Redis容器的网络配置:
docker inspect redis
该命令展现了Docker容器的细节,包括配置信息和网络情况。可使用-f标志只获取IP地址:
docker inspect -f '{{.NetworkSettings.IPAddress}}' redis
若是Docker宿主机运行在本地,能够直接使用Redis服务器的IP地址与Redis服务器通讯。
这个方法有两个问题:第一,要在应用程序里对Redis容器的IP地址作硬编码;第二,若是重启容器,Docker可能会改变容器的IP地址。
六、让Docker容器互连
删除以前运行的redis容器和webapp容器:
docker rm -f webapp docker rm -f redis
新建一个redis容器,与以前不一样的是并不公开任何端口:
docker run -d --name redis ivan/redis
启动Web应用程序容器,并把它链接到新的Redis容器上去:
docker run -p 4567 --name webapp --link redis:db -t -i -v $PWD/webapp:/opt/webapp ivan/sinatra /bin/bash
--link编制建立了两个容器间的父子链接。这个标志须要两个参数:一个是要链接的容器名字,另外一个是链接后容器的别名。这个例子中,把新容器链接到redis容器,并使用db做为别名。链接让父容器有能力访问子容器,并把子容器的一些链接细节分享给父容器,这些细节有助于配置应用程序并使用这个链接。(新建立的容器时父容器,链接到的容器时子容器)
链接也能获得一些安全上的好处。容器的端口不须要对本地宿主机公开。
出于安全缘由,能够强制Docker只容许有链接的容器之间相互通讯,须要在启动Docker守护进程时加上--icc=false标志,关闭全部没有链接的容器间的通讯。
也能够把多个容器链接在一块儿。好比,若是想让这个Redis实例服务于多个Web应用程序,能够把每一个Web应用程序的容器和同一个redis容器链接在一块儿。
被链接的容器必须运行在同一个Docker宿主机上。不一样Docker宿主机上运行的容器没法链接。
Docker在父容器里的如下两个地方写入了链接信息:
/etc/hosts文件中有链接指令建立的项,是redis容器的IP地址和该链接的对应的子容器别名。
若是重启了容器,容器的IP地址可能会发生变化。从Docker1.3开始,若是被链接的容器重启了,/etc/host文件中的IP地址会被新的IP地址更新。
在bash环境中运行env查看环境变量,能够看到一些以DB开头的环境变量。Docker在链接webapp和redis容器时,自动建立了以DB开头的环境变量。DB是建立链接时的子容器别名。这些环境变量主要包含如下信息:
这些环境变量会随容器不一样而变化,取决于子容器是如何配置的。
七、测试容器链接状况
须要下载做者代码/code/5/sinatra/webapp_redis中的内容替换原sinatra/webapp的内容,而后后台启动webapp容器的/opt/webapp/bin/webapp。向web服务提交数据(假设映射到宿主机的端口是49160):
curl -l -H 'Accept:application/json' -d 'name=Foo&status=Bar' http://localhost:49160/json
用get方法测试提交状况:
cuil -i http://localhost:49160/json
5.3 Docker用于持续集成(Jenkins)
一、构建Jenkins和Docker容器
书中代码的Dockerfile没法构建成功,多是因为版本升级形成的。去Github上下载更新过的代码把 5/jenkins/Dockerfile和dockerjenkins.sh放入构建环境的文件夹中。
Dockerfile中使用了VOLUME指令。从容器运行的宿主机上挂载一个卷。
构建成功后启动容器:
docker run -p 8080:8080 --name jenkins --privileged -d ivan/dockerjenkins
这里使用了一个新标志--privileged,它能够启动Docker的特权模式,容许咱们以其宿主机具备的全部能力来运行容器,包括一些内核特性和设备访问。这是能够在Docker中运行Docker的必要能力。
让Docker在特权模式运行会有一些安全隐患。在这种模式下运行容器对Docker宿主机有root访问权限。
接下来是一些Jenkins的细节,笔记中略。