定期処理をcrondからJenkins2に置き換えた話

どうも、大曲です。
Oct-passというサービスやってます。

今回は、定期処理をcrondからJenkins2に置き換えた話に関して書きます。

定期処理をJenkins2でやることになった経緯

Oct-passのサービス開始してから、1年以上が過ぎました。
それに伴って扱うデータ量も増えていき、定期処理の時間が長くなり
重複して実行されるようになってきました。
そして、重複されてから調べることが多くなってきたので
ある程度事前に分かるようにしたいと言うことでJenkins2でやることにしました。

crondからの移行に関して満たしたかった点

  • Slackへの通知ができるようにしたい(メールよりもSlackの方が気付くため)
  • タイムアウトなどを設定できるようにしたい
  • 処理の重複が走らないようにしたい
  • 処理をAnsible化して、手動でサーバをいじることを避けたい(Jenkinsおじさん撲滅)

Jenkins2にした理由

  • JenkinsをCIサーバとして使っていたため、慣れている
  • jenkinsfileを使えば、GUIやXMLを弄ることが減って楽
  • jenkinsfileを利用すればshellやAnsibleの実行だったり、処理の流れが把握できる

主に、jenkinsfileがあることが大きいです。

セットアップの方法

https://github.com/oomatomo/ansible-jenkins2

今回は、サンプルとして上記のリポジトリを用意しました。
実際の処理の流れを体験できればいいなと思います。

JenkinsセットアップのAnsibleを実行

# dockerのビルド
docker-compose build dev
# passwordは test です
ssh -p 2222 test@127.0.0.1
# ansibleの実行
ansible-playbook ansible-jenkins2/ansible/jenkins.yml

Jenkinsの初期設定

上記の内容でJenkins2が立ち上がったのでアクセスすると、
Jenkins2の初期設定の画面が出てくるので、設定していきます。

f:id:AdwaysEngineerBlog:20161028163116p:plain

docker内のパスワードを取得して入力します。

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

f:id:AdwaysEngineerBlog:20161028163126p:plain

プラグインのインストールです。
install suggested pluginsを選んでください。

f:id:AdwaysEngineerBlog:20161028163139p:plain

プラグインのインストール中の画面です。

f:id:AdwaysEngineerBlog:20161028163148p:plain

次に、adminユーザーの作成に入ります。
今回は、テストのなのでユーザー名とパスワードを共にtestでお願いします。

これで初期設定は完了して、Jenkinsのトップ画面が表示されます。

Adminユーザーの設定

Admin用の鍵を作成する

sudo -u jenkins ssh-keygen -t rsa -C jenkins

GUIでAdminユーザーの公開鍵を設定します。
http://127.0.0.1/user/test/configure
SSH Public Keysの項目
鍵は、上で作った公開鍵で大丈夫です。
この鍵は、jenkins-cliでジョブを更新するときに必要なので作っておきます。

cat /var/lib/jenkins/.ssh/id_rsa.pub

f:id:AdwaysEngineerBlog:20161028163215p:plain

Ansibleでジョブの作成

ansible-playbook ansible-jenkins2/ansible/jenkins-job.yml

これで、ジョブが二つ登録されています。

jobを実行

f:id:AdwaysEngineerBlog:20161028163228p:plain

masterが更新されると、どのジョブから変更が反映されたか分かります。

f:id:AdwaysEngineerBlog:20161028163235p:plain

はまった点

jenkins-cliでcreate-jobは、鍵認証は必要無いがupdate-jobでは必要だったこと

cliを使ったジョブの作成のコマンドは以下の通りです。
認証は、usernameとpasswordで行っています。

java -jar jenkins-cli.jar -s http://localhost:8080 create-job --username test --password test test1 <  job_config_test1.xml

XMLの更新などで、ジョブの設定変更があった場合にjenkins-cliのupdate-jobを利用します。
この時の認証は、秘密鍵を指定して公開鍵認証を行っています。

java -jar jenkins-cli.jar -s http://localhost:8080 -i /var/lib/jenkins/.ssh/id_rsa update-job test1 < job_config_test1.xml

update-job で公開鍵認証しなければいけないときに、毎回 No such jobと出ていたいので詰まりました。

良かった点

  • 定期処理にどれくらい時間がかかっているか分かる
  • Slackへの通知はやっぱり便利
  • Ansibleでジョブの登録が完結できる

Ansibleでジョブの登録が完結できる

全てのジョブ登録をAnsibleにしたので出来るようにしたので
本番を直接触ることがなくなったので、オペレーションミスが減るのでよかったと思っています。

悪かった点

  • ジョブの追加のために、色々とやらないといけない
  • 失敗した場合のリカバリー処理がない

ジョブの追加のために、色々とやらないといけない

crondを使っていた時は、crontab -e でいじっていたり
Ansibleのcronモジュールを使ったりとサクッと追加できるのですが。

Ansibleにjob用のxmlファイルの追加したり、jenkinsfileの追加など・・・
逆にこれが手間だと感じることもあります。

失敗した場合のリカバリー処理がない

現状は、手動でビルド実行ボタンをGUIでポチッと押している。
もっといい感じのリカバリー処理無いかなと探しています。
一度失敗したら、一定期間は定期実行をしないとかできたらいいなと考えています。。

これからやりたいこと

  • 失敗した場合の処理、リカバリーの処理の追加
  • Jenkins自体のバッグアップ等々
  • jenkinsfileで利用できるプラグインの更新

jenkinsfileで利用できるプラグインの更新

上のサンプルのリポジトリのjenkinsfileでは、Slackへの通知をcurlを使っていましたが
ちゃんとSlackのプラグインが簡単に書けるように対応しているみたいです。
https://jenkins.io/blog/2016/07/18/pipline-notifications/

このように、jenkinsfileで書けるように各プラグインが対応してきているので
もっとできることが増えると思うので定期的にリプレースできればいいなと考えています。

crondからの移行に関して満たしたかった点の振り返り

とりあえず、満たしたいことは全部出来たのでよかったなと思っています。

Slackへの通知ができるようにしたい(メールよりもSlackの方が気付くため)

jenkinsfileで対応できました。

// Slackへの通知
def notifySlack(text, channel) {
    def slackURL = ''
    def jenkinsIcon = 'https://wiki.jenkins-ci.org/download/attachments/327683/JENKINS?version=1&modificationDate=1302750804000'
    def payload = JsonOutput.toJson([text      : text,
                                     channel   : channel,
                                     username  : "jenkins",
                                     icon_url  : jenkinsIcon])
    sh "curl -X POST --data-urlencode \'payload=${payload}\' ${slackURL}"
}
// 使い方
notifySlack("build failed ${env.JOB_NAME} <!channel>", "#test")

タイムアウトなどを設定できるようにしたい

jenkinsfileで対応できました。

// 分単位の設定が出来る。1分以上処理にかかったらエラーとなる
timeout(1) {
  処理....
}

処理の重複が走らないようにしたい

Jenkinsのジョブの設定でビルドの並列ができないように設定しました。

処理をAnsible化して、手動でサーバをいじることを避けたい(Jenkinsおじさん撲滅)

ジョブの登録を全てAnsibleで出来るようになりました。

サービスでの現状

Jenkins2は、6,7月から利用しています。
ただ、全ての定期処理をJenkins2に移行したわけではありません。
Oct-passの改善の週があるのでその週で既存のものを移行したり、
新規の定期処理をJenkins2で行っていたりしてます。

あと、本番ではテスト用で簡単にjenkinsfileを設定できるジョブを登録して
このjenkinsfileの書き方はあっているか?正常に動くのかチェックしています。

最後に

現状だと、Jenkins2にした良かったと思っています。

あとciサーバは、自分がJenkinsおじさんとなっているので
テストのジョブもjenkinsfileにしてJenkinsおじさんを撲滅したいです。