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的細節,筆記中略。