6.1 使用Jekyll框架和Apache構建應用html
須要構建兩個鏡像:node
工做流程以下:python
這個例子能夠看作是建立一個多主機站點最簡單的方法。git
一、Jekyll基礎鏡像github
創建構建環境:web
mkdir jekyll cd jekyll touch Dockerfile
編寫Dockerfile:redis
FROM ubuntu:14.04 MAINTAINER James Turnbull <james@example.com> 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,會報錯。docker
在Dockerfile中使用VOLUME指令建立了兩個卷:apache
最後,將工做目錄指定爲/data,並經過ENTRYPOINT指令指定自動構建的命令,這個命令將工做目錄/data/中全部的Jekyll網站代碼構建到/var/www/html/目錄中。npm
二、構建Jekyll基礎鏡像
docker build -t ivan/jekyll .
三、Apache鏡像
創建構建環境:
mkdir apache cd apache touch Dockerfile
編寫Dockerfile:
FROM ubuntu:14.04 MAINTAINER James Turnbull <james@example.com> 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。
四、構建Apache鏡像
docker build -t ivan/apache .
五、啓動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標誌把指定容器裏全部的卷加入新建的容器裏。
若是刪除了最後一個使用卷的容器,卷就被刪除了。因此刪除有卷的容器時要當心。
這樣整個服務就啓動好了。
六、備份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目錄裏的全部內容)。
七、擴展Jekyll示例
6.2 構建一個Java應用服務(Tomcat)
一、WAR文件獲取器
建立構建環境
mkdir fetcher cd fetcher touch Dockerfile
編寫Dockerfile
FROM ubuntu:14.04 MAINTAINER Ivan Jiang <ivanjz93@163.com> 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的幫助。
二、獲取WAR文件
docke run -t -i --name sample ivan/fetcher https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war
三、構建Tomcat7應用服務器
建立構建環境:
mkdir tomcat7 cd tomcat7 touch Dockerfile
編寫Dockerfile:
FROM ubuntu:14.04 MAINTAINER Ivan Jiang <ivanjz93@163.com> 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 .
四、運行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 多容器的應用棧
一、Node.js鏡像
建立構建環境:
mkdir nodejs cd nodejs touch Dockerfile
編寫Dockerfile:
FROM ubuntu:14.04 MAINTAINER James Turnbull <james@example.com> 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 .
二、Redis基礎鏡像
mkdir redis_base cd redis_base touch Dockerfile
FROM ubuntu:14.04 MAINTAINER James Turnbull <james@example.com> 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 .
三、Redis主鏡像
mkdir redis_primary cd redis_primary touch Dockerfile
FROM ivan/redis MAINTAINER James Turnbull <james@example.com> ENV REFRESHED_AT 2014-06-01 ENTRYPOINT [ "redis-server", "--logfile /var/log/redis/redis-server.log" ]
docker build -t ivan/redis_primary
四、Redis從鏡像
mkdir redis_replica cd redis_replica touch Dockerfile
FROM ivan/redis MAINTAINER James Turnbull <james@example.com> 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 .
五、建立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參數作相同的處理。
六、建立Node容器
docker run -d --name nodeapp -p 3000:3000 --link redis_primary:redis_primary ivan/nodejs
在瀏覽器中用 宿主機IP:3000測試。
七、捕獲應用日誌
使用Logstash捕獲日誌並將日誌保存到日誌服務器。
mkdir logstash cd logstash touch Dockerfile
FROM ubuntu:14.04 MAINTAINER James Turnbull <james@example.com> 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 <signal> <container>
這個操做會發送指定的信號給容器,而不是殺掉容器。
可使用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}} <container>)
而後運行下面的命令進入容器:
nsenter --target $PID --mount --uts --ipc --net --pid
也能夠將容器內執行的命令添加在nsenter命令行的後面:
nsenter --target $PID --mount --uts --ipc --net --pid ls