LoginSignup
10
7

More than 5 years have passed since last update.

(WIP) jenkins+Docker+GitBucket+Electronでのビルド環境構築

Posted at

TL;DR

GitBucketとJenkins、Dockerを使ってビルドやテストのためのCI環境を構築するための手順。

まだ書いていないこと

  • SSH鍵の登録方法
  • Jenkinsの設定は一通りinit.groovyで行うようにしてしまう
  • Dockerのディレクトリは-vで適切に設定する
  • Electronのサンプルソース

やりたいこと

  1. GitBucketの任意のグループとしてプライベートリポジトリを作成し、ビルド用のJenkinsファイルを配置する。
  2. Jenkins上からGitHub Organization folderを経由してGitBucketに接続し、ビルド対象リポジトリをスキャン
  3. GitBucketのPullRequestのタイミングでJenkinsのビルドが起動
  4. JenkinsのビルドはDockerPluginを通してDockerサーバーをslave起動して、ビルドを行う
  5. 結果をGitBucketにStatusAPIを通して通知する

イメージ

絵に書くとこんな感じになります。シンプルです。
1f117eec-715a-42b8-babb-71ea790a7c09.png

ゴール

GItBucketでPullRequestを出したら実行可能なexe(Electronアプリ)が生成される

エンドユーザー(GItBucket)からの要求を、SIer(Jenkins)が下請け(Docker)に流して働かせ、なにくわぬ顔で成果物を手に入れます。と言ったら一部の方には想像しやすいですかね?

主な登場人物

Jenkins

CIサーバー。バージョンは2.39。AmazonLinux2016.09上に生息。

Master-Slave構成を構築します。SlaveはDockerインスタンスとして稼働させるため、実行時はMasterからDockerサーバーに接続します。
GitBucketと連携するためにGitHub Organization folderを、DockerSlaveを利用するために、Docker Pluginを今回利用します。

GitBucket

GitHubクローン。バージョンは4.8。AmazonLinux2016.09上に生息。

GitHubは使えないけどGitBucketは社内で利用できる人 が今回の対象。GitHubが使える幸せな人は読む必要ありません。GitBucketのAPIをGitHub Organization Folderを利用して無理やり幸せになろうとしています。

なお、GitBucketのAPIの不足分を補うためにJekninsから直接GitBucketに接続するのではなく、
Jenkins <==> Nginx <==> GitBucketという流れを踏むことになります。

Docker

コンテナベースの仮想環境。バージョンは1.12.1(APIは1.24)。CoreOS alpha (1214.0.0)上に生息。
alphaはたまたま。

Dockerfileを利用して事前に仮想環境を構築したイメージを準備しておきます。
Jenkinsから接続され、実際のビルドやテストはこのコンテナ内部で実行されます。

環境構築

サーバー バージョン 同居するモジュール
Jenkins 2.39 Nginx
GitBucket 4.8 Jetty
Docker 1.12.1 (コンテナ上に) nodejs

GitBucketサーバー

インストールから起動

  1. GItBucket4.8をダウンロードします。
  2. 好きなアプリケーションサーバー(私はJetty)に配置して起動します。
  3. http://GITBUCKET_SERVER:8080でアクセスできることを確認してください(ここでは便宜的にGITBUCKET_SERVERというhost名で進めていきます)。
  4. ルーティング用にWebサーバーをインストールします(私はNginxを入れました)。
  5. Nginxの設定を以下のように書き換えます
    (参考:Multibranch PipelineによるJenkinsとGitBucketの連携)。

    /etc/nginx/nginx.conf
    # serverの定義に以下をlocation設定を追加します
    location ~ ^/[^/]+/[^/]+\.git.*$ {
            return http://GITBUCKET_SERVER:8080/git$request_uri;
    }
    
    location ~ ^/api/v3/users/(.*)$ {
            try_files $uri /api/v3/orgs/$1;
    }
    
    location / {
            proxy_pass http://GITBUCKET_SERVER:8080;
            client_max_body_size 10M;
            proxy_set_header Host $host;
    }
    
  6. Nginxの設定を反映させます

    nginx -s reload
    
  7. http://GITBUCKET_SERVER/でアクセスできることを確認します。

  8. root/root(初期ユーザー)でログインし、任意のグループを作成します(ここではJGROUPという名前のグループを作ります)。

  9. Nginxを経由したことでGitBucketでは受け付けていなかった以下のAPIが実行できるか確認します。

    # jqはお好みで
    $ export GITBUCKET_SERVER=127.0.0.1
    $ export GROUP_NAME=JGROUP
    # nginxの設定をしていない場合は、{ "message": "Not Found" } が返る
    $ curl http://$GITBUCKET_SERVER:8080/api/v3/users/$GROUP_NAME | jq .
    {
      "message": "Not Found"
    }
    # nginxの設定をしている場合はグループの情報が返る
    $ curl http://$GITBUCKET_SERVER/api/v3/users/$GROUP_NAME | jq .
    {
      "login": "JGROUP",
      "email": "JGROUP@devnull",
      "type": "Organization",
      "site_admin": false,
      "created_at": "2016-01-19T00:55:00Z",
      "url": "http://GITBUCKET_SERVER:8080/api/v3/users/JGROUP",
      "html_url": "http://GITBUCKET_SERVER:8080/JGROUP",
      "avatar_url": "http://GITBUCKET_SERVER:8080/JGROUP/_avatar"
    }    
    

ユーザー設定とリポジトリ作成

  1. GitBucketにログインします。
  2. Jenkins用のユーザーアカウントを追加します。
  3. Jenkins用のSSH鍵を登録しておきます(TODO)。
    1. http://GITBUCKET_SERVER:8080/jenkins/_sshへ移動
    2. 秘密鍵を2つ登録します(登録の仕方は省略)。
      • jenkins => jenkinsマスターから接続を行うためのssh鍵情報です。
      • jenkins-slave => Docker上のインスタンスから接続を行うためのssh鍵情報です。
  4. 上記で作ったJGROUPに作成したjenkisユーザーを追加し、グループに任意のリポジトリを作成します。
  5. テスト用のリポジトリに以下のようなJenkinsfileを登録しておきます。

    Jenkinsfile
    node("ubuntu-base") {
        stage("hello") {
            echo "world"
        }
    }
    

    これでGitBucket側の設定は終了です。

Dockerサーバー

Dockerサーバーの設定

  1. 好きなDokcerのホストーサーバーを起動します(私の場合はCoreOSを選択)
  2. tcpプロトコルで外部から接続可能なように設定を変更します

    1. docker-tcp.socketを設定します。

      /etc/systemd/system/docker-tcp.socket
      [Unit]
      Description=Docker Socket for the API
      
      [Socket]
      ListenStream=2376
      BindIPv6Only=both
      Service=docker.service
      
      [Install]
      WantedBy=sockets.target
      

      注意事項 (参考:インターネットの向こう側にあるDockerを使う)

      • tcpでの接続を全許可していますのでセキュリティ的に問題があります。
      • 当初Protect the Docker daemon socketで設定しようとしたのですが、JenkinsのDockerPluginがtcpかunixプロトコルしか受け付けていなかったため、あきらめました(実際にはインフラレベルでIP単位でアクセス制限をかけるつもりです。まだやってないけど)。
    2. dockerのプロセスを再起動します

      $ sudo systemctl enable docker-tcp.socket
      $ sudo systemctl stop docker
      $ sudo systemctl start docker-tcp.socket
      $ sudo systemctl start docker
      
  3. 接続確認をします。Jenkinsサーバーからcurlが通るか確認します。

    $ curl http://127.0.0.1:2376/images/json
    

ベースイメージの構築

  1. Jenkinsから接続することが可能なベースとなるDockerImageを構築します。
    今回はこんな感じにベースとなるDockerfileを構築しました(雑です)。

    FROM ubuntu:16.10
    
    #-----------------------------------------------------------
    
    # 各種必要なライブラリのインストール
    # jenkinsユーザーの追加
    # ssh接続を許可
    # 一部後述するelectronの環境構築に必要なライブラリを含む
    RUN set -x \
      && apt-get update \
      && apt-get -y install --no-install-recommends \
          sudo \
          software-properties-common \
          openssh-server \
          curl \
          wget \
          git \
          unzip \
          zip \
          apt-transport-https \
      && mkdir ~/.ssh \
      && mkdir /var/run/sshd \
      && groupadd jenkins && useradd -d /home/jenkins -g jenkins -m jenkins \
      && mkdir /home/jenkins/.ssh \
      && rm -rf /var/lib/apt/lists/*
    
    # 22ポートを公開     
    EXPOSE 22
    
    # jenkinsからgitbucketへ接続するための認証情報を設定
    # http接続ができないのでsshで接続する必要があります
    COPY files/config ~/.ssh/config
    COPY files/config /home/jenkins/.ssh/config
    COPY files/id_jenkins_rsa.pub /home/jenkins/.ssh/authorized_keys
    COPY files/id_gitbucket_rsa /home/jenkins/.ssh/id_rsa
    
    RUN set -x \
      && chown -R jenkins:jenkins /home/jenkins/.ssh \
      && chmod 700 /home/jenkins/.ssh \
      && chmod 600 /home/jenkins/.ssh/*
    
    
  2. インストールします

    $ cd ubuntu-base
    $ find .
    .
    ./files
    ./files/id_gitbucket_rsa
    ./files/id_jenkins_rsa
    ./files/config
    ./files/id_jenkins_rsa.pub
    ./files/id_gitbucket_rsa.pub
    ./Dockerfile
    ./README.md
    $ docker build -t ubuntu:ubuntu-base .
    
  3. Electronのビルド環境構築のためのDockerImageを作ります

    FROM ubuntu:16.10
    
    #---------------------------
    WORKDIR /usr/local
    
    ENV NDENV_ROOT /usr/local/ndenv
    ENV PATH "$NDENV_ROOT/bin:$PATH"
    
    # ビルド用にndenvとyarnをインストールする
    RUN set -x \
      && git clone https://github.com/riywo/ndenv.git /usr/local/ndenv \
      && mkdir /usr/local/ndenv/plugins \
      && git clone https://github.com/riywo/node-build.git /usr/local/ndenv/plugins/node-build \
      && (\
          echo 'export NDENV_ROOT=/usr/local/ndenv'; \
          echo 'export PATH="$NDENV_ROOT/bin:$PATH"'; \
          echo 'eval "$(ndenv init -)"' \
        ) >> /etc/profile.d/ndenv.sh \
      && ndenv install v6.1.0 \
      && ndenv global v6.1.0 \
      && chmod +777 -R /usr/local/ndenv \
      && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - \
      && echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list \
      && sudo apt-get update \
      && sudo apt-get install yarn -y
    
  4. インストールします

    $ cd ubuntu-electron
    $ find .
    .
    ./files
    ./files/id_gitbucket_rsa
    ./files/id_jenkins_rsa
    ./files/config
    ./files/id_jenkins_rsa.pub
    ./files/id_gitbucket_rsa.pub
    ./Dockerfile
    ./README.md
    $ docker build -t ubuntu:ubuntu-electron .
    

以上でDockerサーバーの設定は完了です。

Jenkinsサーバー

インストールから起動

  1. JenkinsのLTS Releaseをダウンロードします。
  2. お好きなアプリケーションサーバー(私はJetty)に配備します。ただしまだ起動はしません。
  3. Jenkinsはデフォルトでは$HOME/.jenkins以下に必要なデータを構築しますので、事前に$HOME/.jenkinsディレクトリを作成して、$HOME/.jenkins/init.groovyという名前で以下のファイルを配置します。
    (参考:Jenkinsの公式Dockerイメージ使ってみた)

    init.groovy
    import hudson.model.*;
    import hudson.security.*
    import jenkins.model.*;
    
    def instance = Jenkins.instance
    
    //  ログインユーザーを自動生成
    // https://groups.google.com/d/msg/jenkinsci-users/Pb4QZVc2-f0/5hzCC-syNgAJ
    def hudsonRealm = new HudsonPrivateSecurityRealm(false)
    hudsonRealm.createAccount('admin','admin')
    instance.setSecurityRealm(hudsonRealm)
    
    def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
    instance.setAuthorizationStrategy(strategy)
    instance.save()
    
    def uCenter = instance.updateCenter
    uCenter.updateAllSites()
    
    def checkIfPluginInstalled = { pluginid ->
      for(p in instance.pluginManager.plugins) {
        if(p.shortName == pluginid){
          return true
        }
      }
      return false
    }
    
    // Installs the following plugins if not installed.
    [
      "cloudbees-folder",
      "antisamy-markup-formatter",
      "build-timeout",
      "credentials-binding",
      "timestamper",
      "ws-cleanup",
      "gradle",
      "workflow-aggregator",
      "github-organization-folder",
      "pipeline-stage-view",
      "git",
      "ssh-slaves",
      "matrix-auth",
      "pam-auth",
      "ldap",
      "email-ext",
      "mailer",
      "docker-plugin",
      "ghprb"
    ].findAll({! checkIfPluginInstalled(it)}).each {
      uCenter.getPlugin(it).deploy()
    }
    
    // Set the number of executors (in master-node) to 0.
    instance.setNumExecutors(0)
    
    instance.reload()
    
  4. Jenkinsを起動すると、init.groovyが読み込まれてadminユーザーと必要なプラグインがインストールされます。

プラグインの設定

必要なプラグインの設定を行っていきます。

Docker Plugin

  1. http://JENKINS_SERVER:8080/configureへ(Jenkinsの管理 => システム設定)。
  2. クラウド => 追加 => Dockerを選択

    • 各種設定を行います
      577c18fd-3e7f-4803-9d34-c2f4b1bafc9a.png
      • Nameは任意
      • Docker URLはtcpあるいはunixのみが指定可能です。httpは不可
      • Docker API VersionはCoreOS上でdocker versionと打つことで確認できます。
    • Images => Add Docker Templateで利用するDocker名を紐つけます。
      aab5a067-4347-4e2c-af50-c7499739e89b.png
      • Docker Image => Dockerの設定で作成したImage名を指定します。
      • Remote Filing System Root => Dockerfileで作成したjenkinsユーザーのhomeディレクトリを指定します
      • Label => Jenkinsfileのnodeの指定となるslave名です。
      • 用途 => このマシーンを特定ジョブ専用にするを選択します。
      • Lanunch method => Docker SSH computer launcherを選択します。認証情報は、Dockerfile内で定義した秘密鍵を使います。
    • ImagesのConfiguration setting... => Volumesでキャッシュしたいディレクトリを永続化しておきます。 今回はyarnのキャッシュフォルダとelectronのバイナリをホスト側にマウントするために以下の設定を追加しています。
      /home/core/cache/yarn:/home/jenkins/.cache/yarn/
      /home/core/cache/electron:/home/jenkins/.electron/
    

GitHub Organization Folder

  1. http://JENKINS_SERVER:8080/configureへ(Jenkinsの管理 => システム設定)。
  2. GitHub Enterprise Serversを設定します。
    60617ccd-9aed-4ba3-866e-0fdbac6c31c0.png
    • API endpoint => http://GITBUCKET_SERVER/api/v3/
    • Name => 適当に(AWS-GITとつけました)

JOB作成

  1. 新規ジョブでGitHub Organization Folderを作成します。 任意の名前をつけることが可能ですが、設定した名前がリポジトリのowner(ユーザーorグループ)になります。対象のリポジトリグループは後で変更可能です。6a794f28-f792-4a63-b17c-11f82ba8fa5d.png
  2. 設定画面が開くので、Project SourcesからRepository Sources の設定を行います。4901e517-357d-437e-84b5-88724943aee3.png
    • Owner --- 指定したユーザーorグループのリポジトリ以下を探索します
    • API endpoint --- 接続先のサーバーをシステム設定で設定したGitBucketの名前を設定します。
  3. うまくいけば指定したグループ配下がスキャンされJenkinsfileが存在するリポジトリが一覧に表示されます。
    • スキャン完了後
      9d32f5cb-06f4-4abd-90b4-84ce68bf2010.png
    • ブランチ一覧
      e8576f72-36b5-471e-aa7a-b657b743bd2c.png
    • ビルド結果
      acffee48-dc5b-4dd9-9210-fe52531680fe.png

ゴールを確認

やりたい事が出来ているか確認します。

  1. GitBucketのリポジトリ上に簡単なElectronアプリをPUSHします。Jenkinsファイルには成果物を保存するところまで記載しておきます( TODO サンプルソース)。
  2. Re-Scanして認識することを確認します。
  3. GitBucket上のリポジトリ上にブランチを切り、PullRequestを出します。
  4. PullRequestが出たタイミングでJenkinsビルドが走ることを確認します。 c8484347-6344-4fbb-9899-c66c8850894b.png 842972e0-adb4-4e16-8fc4-7e003a6eaae8.png
  5. Jenkinsビルドが完了後に成果物がダウンロードできることを確認します。

ハマリポイント(まとめ)

  • GitHub Organization folderでスキャンしてもGitBucketに繋がらない
    • 上記手順にしたがってWEBサーバーでルーティングをいじる必要があります。
  • DockerPluginからProtect the Docker daemon socketできない。
    • 現在のバージョン(DockerPlugin 0.16.2)だとhttpsは設定できません。
  • Slaveとして起動しているDockerのインスタンスにJenkinsから接続出来ない。
    • DockerPluginの接続を確認しましょう。必要な秘密鍵はDockerに接続する認証情報ではなくて、Docker上に存在するインスタンスに接続するための秘密鍵です。
  • Docker上からGitBucketのソースをclone出来ない
    • httpsプロトコルやgitプロトコルでは接続出来ません。sshで接続しましょう。

オチ

GitHubは便利です。でも会社ではGitBucket使い続けていくつもりです。

10
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7