Docker在英雄聯盟游戲中的實踐探索(四)

jopen 9年前發布 | 28K 次閱讀 Docker

這篇博客是Riot的Docker實踐系列博客的第四篇,主要討論了如何添加一個基于Nginx的代理容器,以及如何用Compose來管理多容器應用。

背景

如果你剛加入我們,可以先從 這篇介紹的文章開始,了解我們是如何完成英雄聯盟的持續發布,以及我們是如何發現這個技術棧可以很好地解決我們的問題。

在我們的 第一篇文章中,我們介紹了如何把Jenkins放在Docker容器中。 第二篇文章中, 我們介紹了如何使用Docker數據卷容器來創建持久化層。我們創建了一個容器,來保存Jenkins相關的文件,以持久化插件、任務和其他的 Jenkins核心數據。我們討論了數據卷容器和宿主機掛載卷之間的區別。最后,為了不持久化Jenkins war文件,我們介紹了如何從Jenkins主目錄中移除war文件。

在第二篇文章的末尾,我們已經有了一個功能完備的、可以保存數據的Jenkins鏡像。然而,由于若干原因,它還不完美。本篇文章將解決其中一個 問題:在Jenkins之前缺少一個web代理。同時,我們將運行3個容器來構建Jenkins環境。本文將分為兩個部分:一是如何添加一個代理容器,二 是如何使用Compose(一種方便的Docker工具)來管理多容器應用。

讀完本文,你將會完成一個全棧(full stack)的Jenkins主服務器。

第一部分: 代理容器

在Riot,我們使用Nginx作為代理,因為它可以容易地重定向至HTTPS,并使Jenkins監聽在 8080端口,web服務器監聽在80端口。這里不會介紹如何配置Nginx的SSL和HTTPS(互聯網上可以找到文檔和實例);相反,我將介紹如何在 容器中運行Nginx代理服務器,并代理Jenkins服務器。

這一部分將涉及以下幾點:

  • 創建簡單的Nginx容器
  • 學習如何從本地目錄中添加文件到鏡像中,比如Nginx配置文件
  • 使用Docker容器鏈接(link),連接Nginx和Jenkins
  • 配置Nginx來代理Jenkins
  • </ul>

    更換OS
    在Riot,我們并不常用Debian;然而,Cloudbees的Jenkins鏡像使用Debian作為默認 OS,繼承自Java 8鏡像。但是,Docker的其中一個強大之處在于,我們可以使用任意的OS,因為宿主機并不在乎。這也展示了容器的“混合模式”。這意味著,如果應用在 多個容器之間運行,它們并不需要是同一個OS。如果某個特定的進程需要使用某個特定的Linux發行版的庫或模塊,這種做法就很有價值了。至于應用在 Debian/Centos/Ubuntu上的擴展性(spread)是否是個好主意,你們可以自行判斷。

    你們可以將鏡像轉換成Ubuntu、Debian,或者任意一個OS。我們將使用CentOS 7。在本文的第四部分,我將會具體地討論如何更換Jenkins鏡像中的默認OS,并移除對于外部鏡像的依賴性。需要考慮的是,如果你更換了OS,那么需 要更改很多命令和配置,來確保Nginx正常工作。

    創建Nginx Dockerfile
    在你的項目根目錄中,創建一個新目錄jenkins-nginx,來保存另一個Dockerfile。現在,你應該有三個目錄了(如果你讀過之前的文章):

    1、設置OS基礎鏡像:

    FROM centos:centos7
    MAINTAINER yourname

    2、使用yum安裝Nginx:

    RUN yum -y update; yum clean all
    RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm; yum -y makecache
    RUN yum -y install nginx-1.8.0

    注意我們使用的Nginx版本是1.8.0。這是一個最佳實踐:總是鎖定版本,避免鏡像的重新構建使用未經測試的版本。

    3、清除不需要的默認Nginx配置:

    RUN rm /etc/nginx/conf.d/default.conf
    RUN rm /etc/nginx/conf.d/example_ssl.conf

    4、添加配置文件:

    COPY conf/jenkins.conf /etc/nginx/conf.d/jenkins.conf
    COPY conf/nginx.conf /etc/nginx/nginx.conf


    這是我們第一次使用COPY命令。ADD命令與COPY命令十分類似。如果想透徹地了解兩者的區別,我推薦你閱讀以下鏈接:

    • http://stackoverflow.com/quest ... s-add
    • https://docs.docker.com/articl ... -copy
    • </ul>
      針對我們的場景,COPY是最好的選擇。就像以上文章中推薦的,我們只是拷貝單個的文件,并不需要ADD命令提供的特性(解壓tarball,基于URL的獲取等)。我們會更新默認的nginx.conf和Jenkins的配置文件。

      5、我們希望Nginx監聽80端口:

      EXPOSE 80

      6、啟動Nginx:

      CMD ["nginx"]

      保存文件,但不要構建它。因為Dockerfile中有兩個COPY命令,我們需要首先創建這些文件。否則,如果這些文件不存在,構建將會失敗。

       Docker在英雄聯盟游戲中的實踐探索(四)


      創建Nginx配置文件
      以下的nginx.conf是一個默認配置,然后再修改特定的配置。

      daemon off;
      user  nginx;
      worker_processes  2;

      error_log  /var/log/nginx/error.log warn; pid        /var/run/nginx.pid;

      events {     worker_connections  1024;     use epoll;     accept_mutex off; }

      http {     include       /etc/nginx/mime.types;     proxy_set_header X-Real-IP $remote_addr;     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

          default_type  application/octet-stream;

          log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '                       '$status $body_bytes_sent "$http_referer" '                       '"$http_user_agent" "$http_x_forwarded_for"';

          access_log  /var/log/nginx/access.log  main;

          sendfile        on;     #tcp_nopush     on;

          keepalive_timeout  65;

          client_max_body_size 300m;     client_body_buffer_size 128k;

          gzip  on;     gzip_http_version 1.0;     gzip_comp_level 6;     gzip_min_length 0;     gzip_buffers 16 8k;     gzip_proxied any;     gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json;     gzip_disable "MSIE [1-6].";     gzip_vary on;

          include /etc/nginx/conf.d/*.conf; }</pre>

      現在來修改默認配置:
      1、使Nginx不以daemon方式運行:

      daemon off;

      這是因為命令行中調用nginx,Nginx將以daemon方式運行在后臺。這會返回exit 0,Docker會認為進程已經退出,然后停止容器。你會發現這種現象經常發生。對于Nginx來說,只要簡單地修改下配置就可以解決這個問題。

      2、將Nginx的worker數目提升為2:

      worker_processes 2;

      這是我每次設置Nginx時必定做的事。當然,你可以選擇保持該配置為1。Nginx調優可以單獨寫一篇文章。我不能告訴你什么是對的。粗略地說,該配置 指定了多少個單獨的Nginx進程。CPU數目是一個不錯的參考值,當然,很多NGINX專家會說情況遠比這個要復雜。

      3、事件調優(Event tuning):

      use epoll;
      accept_mutex off;

      打開epolling可以使用高效的連接模型。為了加速,我們關閉了accept_mutex,因為我們不在乎較低的連接請求數造成的資源浪費。

      4、設置代理頭:

      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      除了關閉daemon模式之外,這是第二個必須的Jenkins代理配置。只有這樣,Jenkins才能正確地處理請求,否則會出現一些警告。

      5、客戶端大小:

      client_max_body_size 300m;
      client_body_buffer_size 128k;

      你可能需要這些配置,也可能不需要。不可否認的是,300MB是一個很大的body大小。然而,我們的用戶上傳文件到Jenkins服務器,其中一些是HPI插件,一些是真實文件。

      6、打開GZIP:

      gzip on;
      gzip_http_version 1.0;
      gzip_comp_level 6;
      gzip_min_length 0;
      gzip_buffers 16 8k;
      gzip_proxied any;
      gzip_types text/plain text/css text/xml text/javascript application/xml application/xml+rss application/javascript application/json;
      gzip_disable "MSIE [1-6]\.";
      gzip_vary on;

      為了加速,我們打開了gzip壓縮。

      保存文件為conf/nginx.conf。下一步就是為Jenkins添加特定的配置文件。

       Docker在英雄聯盟游戲中的實踐探索(四)


      針對Jenkins的NGINX配置
      就像上一章那樣,我會先提供一份完整的配置文件,然后再修改特定的配置。你會發現大多數內容可以在Jenkins的 官方文檔找到。

      server {
          listen       80;
          server_name  "";

          access_log off;

          location / {         proxy_pass         http://jenkins-master:8080;

              proxy_set_header   Host             $host;         proxy_set_header   X-Real-IP        $remote_addr;         proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;         proxy_set_header   X-Forwarded-Proto http;         proxy_max_temp_file_size 0;

              proxy_connect_timeout      150;         proxy_send_timeout         100;         proxy_read_timeout         100;

              proxy_buffer_size          8k;         proxy_buffers              4 32k;         proxy_busy_buffers_size    64k;         proxy_temp_file_write_size 64k; 

          }

      }</pre>
      只有一個配置,是真正關于代理的:

      proxy_pass   http://jenkins-master:8080;

      這個配置需要域名jenkins-master存在,這個可以通過容器連接來保證(稍后會講到)。如果你還沒使用容器連接的話,那么需要將映射Jenkins容器的IP/hostname。

      然而,你不能把它設置為localhost。這是因為每個Docker容器都有自己的localhost, 將代理指向了Nginx容器本身,這里并沒有運行在8080端口的Jenkins。為了避免使用容器連接,需要執行Docker Host(應該是你的Desktop或laptop)的IP地址。盡管你是知道這個信息的,但是請想象一下,如果你的Jenkins容器是運行在 Dockerhost集群中的任意一臺。你需要寫一個自動腳本,來獲取IP地址,然后編輯配置文件。這是可以做到的,但是非常麻煩。容器連接可以簡化這一 過程。

       Docker在英雄聯盟游戲中的實踐探索(四)


      構建Nginx鏡像,并連接到Jenkins鏡像
      現在,我們已經創建了Nginx和Jenkins的配置文件。請確保你是在頂層目錄中。

      docker build -t myjenkinsnginx jenkins-nginx/.

      構建完成之后,我們可以啟動它,并連接到jenkins-master鏡像,使代理發生作用。首先,請確保jenkins-data和jenkins-master正在運行。

      docker run --name=jenkins-data myjenkinsdata


      如果發生了錯誤,不用緊張,這說明容器已經存在了。這是一個好事,因為這意味著我們沒有覆蓋原來的數據。

      docker stop jenkins-master
      docker rm jenkins-master
      docker run -p 8080:8080 -p 50000:50000 --name=jenkins-master --volumes-from=jenkins-data -d myjenkins

      現在,我們終于可以啟動Nginx容器,并連接jenkins-master:

      docker run -p 80:80 --name=jenkins-nginx --link jenkins-master:jenkins-master -d myjenkinsnginx

      請注意--link參數。你可以在 Docker官方網站上找到相關文檔。需要確保域名"jenkins-master"在NGINX容器中存在,指向jenkins-master容器的內部Docker網絡IP。

      請注意Nginx容器必須在jenkins-master容器之后啟動。這意味著,如果要停止和重啟jenkins-master容器,那么也需要重啟Nginx容器。

       Docker在英雄聯盟游戲中的實踐探索(四)


      測試一切是否正常很容易。只要在瀏覽器中輸入IP地址,一切應該正常工作了。

      如果出了問題,那么一定有什么東西阻塞了80端口(這更可能發生在OSX上)。請確保防火墻已經關閉,或者至少可以接受80端口的流量。如果由于某種原因,你不能清除80端口,請關閉并刪除jenkins-nginx容器,以-p 8000:80參數重啟它。然后,訪問 http://yourdockermachineip:8000,看看一切是否正常。

      Jenkins鏡像清理
      我們已經讓Nginx監聽在80端口了,就不需要Jenkins鏡像暴露8080端口了。現在我們需要刪除這個端口配置。停止并重啟Jenkins容器,同時Nginx容器也需要重啟,因為兩者是連接在一起的。每次重啟時,它們都會連接在一起。

      docker stop jenkins-nginx
      docker stop jenkins-master
      docker rm jenkins-nginx
      docker rm jenkins-master
      docker run -p 50000:50000 --name=jenkins-master --volumes-from=jenkins-data -d myjenkins
      docker run -p 80:80 --name=jenkins-nginx --link jenkins-master:jenkins-master -d myjenkinsnginx

      刷新瀏覽器 http://yourdockermachineiphere

      已經不能訪問8080端口了,相反,可以通過Nginx代理訪問它了。

       Docker在英雄聯盟游戲中的實踐探索(四)


      與往常一樣,代碼和示例都可以在GitHub上找到,地址是 https://github.com/maxfields20 ... al_04。你會注意到makefile更新了,添加了Nginx容器和Jenkins容器的啟動順序。

      Docker Compose和Jenkins

      我們現在運行了3個容器,一個是Nginx代理容器,一個是Jenkins應用容器和一個保存Jenkins數據的數據卷容器。我們已經發現,因為數據卷和容器連接,這3個容器之間有啟動順序和依賴。本文將介紹Compose來處理這些。

      本小節將涉及:

      • 使用Compose來管理多容器應用
      • </ul>

        什么是Compose
        Compose是從另一個工具Fig發展而來的。Docker將它定義為“運行復雜應用的工具”。你可以從 https://docs.docker.com/compose/查看相關文檔。當運行應用時,Compose可以幫我們構建鏡像,決定停止和啟動哪些容器。

        例如,如果我希望運行3個容器應用,重新構建Jenkins容器,重新運行應用-可能是升級Jenkins版本。請運行以下命令:

        docker stop jenkins-nginx
        docker stop jenkins-master
        docker rm jenkins-nginx
        docker rm jenkins-master
        docker build -t myjenkins jenkins-master/.
        docker run --name=jenkins-master --volumes-from=jenkins-data -d myjenkins
        docker run -p 80:80 --name=jenkins-nginx --link jenkins-master:jenkins-master -d myjenkinsnginx

        正確配置之后,我們可以運行Compose:

        docker-compose stop
        docker-compose build
        docker-compose up -d

        這和makefile的行為很類似。使用Compose的取舍在于,你必須額外再維護一個配置文件。

        本小節單獨成章,是因為使用Docker-Compose是一個個人選擇。然而,如果你有很強的Windows開發背景,那么Compose可能不是一個很好的選擇。

        需求

        • 如果你在OSX上使用Docker Toolbox, Compose是默認安裝的。
        • 如果你還沒安裝Docker Toolbox,或者使用Linux,那么請參考https://docs.docker.com/compose/install/安裝Compose
        • OSX 或者 Linux
        • </ul>
          請注意,Compose還不能在Windows上與Windows版本的Docker客戶端一起運行。如果你使用的是Windows和 Docker Toolbox,情況會有所不同。我的建議是暫時使用makefile。Compose的開發團隊正在開發Windows兼容版本,但是1.4版本尚不支 持。

          第一步:創建Compos配置文件
          Compose使用YAML配置文件。我們為每一個需要Compose管理的鏡像添加一個條目。

          • 在你的項目根目錄中,創建一個文件docker-compose.yml
          • </ul>
            你完全可以使用另外一個名字,但是默認情況下,Compose將首先查找這個名字。

            第二步: Jenkins數據容器
            編輯docker-compose.yml,添加以下內容(由于它是yaml,所以需要保持縮進):

            jenkinsdata:
             build: jenkins-data

            以上是創建了一個容器的條目,叫做“jenkinsdata”。Compose不支持名字中的特殊字符,如“-”。然后,我們添加了一個構建目錄,名字是Dockerfile所在的目錄名,如“jenkins-data”。

            檢查一切是否正常:

            1. 保存文件。
            2. 執行docker-compose build。
            3. </ol>

               Docker在英雄聯盟游戲中的實踐探索(四)


              Docker-Compose會找到jenkins-data目錄,構建Dockerfile,就像執行了docker build jenkins-data/一樣。你會注意到,鏡像的名字是不同的。Compose使用的命名轉換是“projectname_composecontainername”。默認情況下,項目名稱是父目錄的名字。

              這種命名標準是相當重要的。這是產品環境中的容器命名方式。請確保父目錄的名字是合理的,或者使用-p來制定鏡像名稱。你也可以使用-p來區別產品環境和開發環境。

              第三步: Jenkins主鏡像
              繼續編輯docker-compose.xml,添加以下內容:

              jenkinsmaster:
                build: jenkins-master
                volumes_from:
                  - jenkinsdata
                ports:
                  - “50000:50000”

              就像Jenkins數據鏡像一樣,我們也有一個條目,來命名容器,并定義構建目錄。我們也加了一條volumes_from語句,與命令行中的--volumes-from=的作用相同。但是,請注意Compose使用的容器名并不是真正的名字。這是Compose的一個方便的特性,可以讓我們引用這些名字,提高可讀性。Compose足夠聰明,可以把它們組合在一起,來構建容器。

              另一個優勢是Compose知道jenkinsmaster依賴于jenkinsdata,因此會以正確的順序來啟動它們。你可以在Compose文件中以任意順序列舉它們。

              最后,我們使用ports指令,來處理端口映射。為了JNLP從連接,我們需要確保Jenkins主容器做50000端口映射。

               Docker在英雄聯盟游戲中的實踐探索(四)


              第四步:Nginx鏡像

              jenkinsnginx:
                build: jenkins-nginx
                ports:
                   - "80:80"
                links:
                   - jenkinsmaster:jenkins-master
               

              將像其他兩個條目,它也有一個名字(jenkinsnginx)和一個構建目錄。但是,我們添加了一條links指令,就像命令行中的--link。

               Docker在英雄聯盟游戲中的實踐探索(四)


              第五步:將所有這些組合在一些
              完整的docker-compose.yml:

              jenkinsdata:
               build: jenkins-data
              jenkinsmaster:
               build: jenkins-master
               volumes_from:
                - jenkinsdata
               ports:
                - "50000:50000"
              jenkinsnginx:
               build: jenkins-nginx
               ports:
                - "80:80"
               links:
                - jenkinsmaster:jenkins-master

              我們需要構建所有這些。首先,需要確保沒有之前的容器的痕跡。如果你已經清理了,你可以跳過這一步:

              docker stop jenkins-nginx
              docker rm jenkins-nginx
              docker stop jenkins-master
              docker rm jenkins-master
              docker rm jenkins-data

              注意:遷移到新模型,我們只能丟掉數據容器,這很討厭。在未來的文章中,我將會討論如何備份數據。但是如果你需要備份這些數據的話,你可以先用 第三篇的docker up來備份數據。

              docker-compose build
              docker-compose up -d

              注意-d使得Docker-Compose以daemon方式運行容器,就像Docker的參數-d一樣。如果你想知道哪些容器正在運行,Docker-Compose也有相類似的特性:

              docker-compose ps

               Docker在英雄聯盟游戲中的實踐探索(四)


              第六步:使用Compose維護
              Compose足夠聰明到了解數據卷,并持久化。

              • 在Jenkins實例中,創建一條測試任務

                docker-compose stop
                </li>

              • 簡單地編輯一下Jenkins主Dockerfile,例如更改MAINTAINER。

                docker-compose build
                docker-compose up -d
                </li>

              • 回到Jenkins實例,查看測試任務是否已經存在。
              • </ul>
                Docker Compose會啟動數據容器,并重新創建Nginx容器和主容器。

                Compose有一個簡單的方式來清理所有的東西:

                docker-compose rm

                這條命令也會刪除你的數據容器。如果你不愿意刪除數據容器的話,也很簡單。

                docker-compose rm jenkinsmaster jenkinsgninx


                 Docker在英雄聯盟游戲中的實踐探索(四)


                總結
                你可以在 https://github.com/maxfields20 ... al_05上找到代碼和實例。

                我們了解到Compose可以簡化多鏡像應用的管理,只需要多加一個配置文件。這個文件用來自描述容器之間的關系。

                Compose是一個不錯的、可操作的工具。可能的一個缺點是,容器名是基于父目錄而定的,總是需要你指定一個項目名稱。Compose可以使用PS和RM等工具。

                我們也了解到Compose還不能在Windows上運行。你是否使用Compose取決于你是否需要Windows支持,或者你是否喜歡 Compose的命名方式。我個人很喜歡docker-compose.yml的自描述方式。你會注意到我仍然提供了makefile,因為我不需要記住 所有容器的名字。

                至此,基礎教程結束了。之后的文章將涉及更高級的內容。

                下一步

                我們還有三個高級話題:備份,構建從節點和Docker鏡像的完全控制。我將會討論如何完全制作你自己的Jenkins 鏡像,而不需要依賴公共倉庫。主要是因為依賴管理,或者是因為你不喜歡基于Debian的容器,更喜歡Ubuntu或者CentOS。因此,之后我們會從 頭創建自己的Dockerfiles,來構建從容器。接下來的內容是:

                1. 完全控制所有的鏡像
                2. 備份Jenkins鏡像
                3. 構建從容器
                4. </ol>
                  下次再會!

                  原文鏈接:JENKINS, DOCKER, PROXIES, AND COMPOSE(翻譯:夏彬 校對:李穎杰)

                  來自:http://dockone.io/article/820

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!