「2015 新春 JJUG 特別企画 Jenkins まつり」に参加しました
http://jjug.doorkeeper.jp/events/19259
先に感想
- Oracle来たこと無い(あったかも。忘れた)と、どこ行っていいかわからんかった。
- スーツ率高め。7割ぐらい?
- Slack使ってる人がほとんど手が上がらなかったのが、ちょっと衝撃的。
- プラグインいっぱい。実運用する前に、プラグインテスト用の環境が欲しい。作ろう。
- UrbanCodeは、自分がエンタープライズじゃないからあんまり関係無い気がした。
- 川口さんの話は、最初何を話しているのかわかんなかった。ついていけてからは面白かった。
- 広い範囲を上手く自動化していきたい。
- 荷物だけあって、結局誰も来なかった席は何だったんだろう。
Javaユーザに贈るJenkins 25のTips
Jenkins実践入門書いた人
必須
- Gitプラグイン
Validated Mergeプラグイン(エンタープライズ限定) - Githubプラグイン
webhookでプッシュ。ポーリングじゃない。 - Gradleプラグイン
gradleラッパーでもできるけど、スレーブとか使うとき便利
コーディング中のやつ
- checkstyleプラグイン
- FindBugsプラグイン
- TaskScannerプラグイン
TODO / FIXMEを警告にしてくれる
ジョブの設定系
- JobConfigHistoryプラグイン
設定の変更履歴を見れる。
ビルド履歴にハンマーマークが出てくる。前回との設定の差分も見れる。
コンソールを見やすくする系
- Timestamper
コンソール出力にタイムスタンプを表示できる。経過時間も見れる。
自分色に染める
- Emotional Jenkinsプラグイン
Jenkinsおじさんが3变化する - chuck norrisプラグイン
チャックノリスさんに - GreenBallsプラグイン
青をグリーンに変えられる - Nested Viewプラグイン
パイプラインプラグイン使った時に、階層構造で表示出来る。
プラグインじゃないTips
- JUnitのテストレポート表示
JUnit互換で出力させると、Rspecの結果も表示できる。 - マルチ構成プロジェクト
Safariはmacだけ、とかをフィルターで出来る - パンくずメニューでショートカット
いろんなメニューが出てくる。 画面遷移を減らせる。 - コンソールにジャンプ
ビルド中の青いメーターをクリックすると、コンソール出力を見れる - safeRestart
/hostname/safeRestartにアクセスすると、再起動出来る
CIを制す
- Deployプラグイン
Glassfish / jboss / tomcat に対応 - Xvfbプラグイン
仮想ディスプレイで、Seleniumなどのブラウザテストが出来る - Build Pipeline Viewプラグイン
Jobの流れをGUIで見やすい - Promoted Buildsプラグイン
だれかが承認した場合のみ実行
3つの並列テストが全て通ったら、とか。 - Workflowプラグイン
一杯プラグインが入る。
Groovy DSLでジョブを書けるようになる。
スニペットもある。
CIを制したら
- Slackプラグイン
- Email-extプラグイン
メールの細かい宛先設定など。 - Disk Usage プラグイン
ディスクをいっぱい使ってると、使ってる感が見える。 - Monitoring
CPUとかメモリとかをモニタリング出来る。グラフで。
Jenkins実践入門は改訂予定のため、まだ電子化されない
継続的インテグレーションから継続的デリバリーへ
- エンタープライズを意識した話。
- 開発部門がさわれなかったり、上長の承認が必要だったり。。。
- 本:継続的インテグレーション入門、オライリーのJenkins
- 本:継続的デリバリー
- ツールの共有が難しい。Dev vs Ops。思いの違い。
- 組織が大きくなっていくと、分担・チェックが多くなる
- CI:ビルドジョブの組み合わせ→CD:環境毎
- CDの領域はDevとOpsが重なる
UrbanCodeの説明・デモ
- プッシュボタン・デプロイメント
- D&Dでフローを作れる
- 細分化したViewもある
- プラグインの活用
Jenkinsとの連携とか、メインフレームに対するデプロイとか
Groovyで書ける - 環境ごとのリリース状況を視覚的に見れる。どのバージョンが入っているかをみれる。
- 品質ゲートの設定
- リリース承認プロセスの定義
- リリース状況のリアルタイム確認
- ログインユーザに依る権限管理
Jenkinsとの違い
ビルドに焦点を当てているか、リリースに焦点を当てるか。
Chef/Puppet + Jenkinsによる継続的デリバリ
会社紹介
- CloudBees
- Jenkins Enterpriseなど、Jenkins周りの開発・サポートなど
背景
- より広域なend-to-endの自動化
- jenkins-ci.org 運用上のニーズ
個々のサービスをコンテナ化
サンプル。 https://github.com/jenkins-infra Puppetの中の人のベストプラクティスが詰まっている。
- git -> Jenkins -> docker
- jenkins-infra/ircbotとか
- rspec-puppetによるプルリクエストの検証
- serverspecによる一時サーバでの検証
- vagrantに適用してみる。EC2でやっている。EC2でやることで、並列に高速に実行できる。
- Vagrantfileに書いてある。
- 今はmasterに対してだけやっている。金があれば、Pull Request単位でもいいんじゃないか。
- r10k + puppet enterprise
- ブランチ名=環境名になる。
- 環境別の際を吸収するHiera
- 階層構造も自由に出来る -> yamlファイルに外出し
- 鍵・秘密の情報の取り扱い
- dockerのpackageに入れなくていい
- hiera-eyaml でパラメータの個別暗号化。eyamlというエディタで変更 -> 保存すると暗号化。鍵は別に保存しておく必要がある。
- ブランチと環境の関係
- Pull Requestをマージすると、自動的に本番に反映される、とか。
ビルド履歴がGitHub上に残る。
- Pull Requestをマージすると、自動的に本番に反映される、とか。
継続的デリバリの課題
- 実際にいつ起こったのか
- 現在のサーバで走っているのはどのビルドか
ファイル指紋
- md5 check sum。
- 自動的に指紋を取る
- テストとビルドが関連づいていなくても、追える
- デモ
- Jenkinsでビルド -> 手動でデプロイ(デプロイ結果をJenkinsに通知) -> Jenkinsでテスト
- Promotionプラグインを入れておくと、デプロイされたことが星印で出てくる
- いつ・なにが・どこにデプロイされたのかを確認できる
- Chefとpuppertにしか対応してないけど、拡張可能な形式で作ってある
- Chefはカスタムレポートハンドラーとして実装
今後の予定
- データの可視化
- ファイルじゃないのもの指紋
- jenkins-ci.orgの運用でも使っていく
from 2014 to 2015
あけましておめでとうございます。
2015年が始まり、数日経ってしまいましたが、2014年のまとめと、2015年の目標を書いておこうと思います。
2014年にやったこと
仕事
- 初のオフショア開発リーダー(?)
短納期で、途中からの引き継ぎだったで、ちゃんとチームでやる気もなく、やってる暇も無かった。
そんな状態かつ、初のオフショアだったもんで、出来たコードが自分の思ったのと大幅に違い、最低限は自分で作りなおすという暴挙にでる。
オフショア恐怖症が、完全に発症。自分がオフショア使うぐらいなら、会社辞めるって公言するレベルに。
お陰様で、その後はオフショアと直接やりとりすることは無くなって良かったです。
- PM業務
iOSアプリの開発で、PM業務をやることになりました。
1回ぐらい経験しておこうかなーというのもあったので、タイミング的には良かったのですが、やっぱり面倒ですね。
見積もりから、外部設計を作り、内部設計を依頼し、実装を確認する。
しまいには実装もし始めたので、てんやわんやに。
やっぱり、マネージャーはマネージメントに徹しないとダメですね。
そして、私はマネージメントに向いてない。
- 初、業務でAndroidアプリ開発
iOSアプリは出来てる状態で、1ヶ月程度で作れという。
突貫工事で作ったため、いろいろとまずい部分があったまま完成はしたけど、上の都合でお蔵入り。
その後、別の方向性で同じ名前のアプリを作りなおして、そっちはちゃんと設計しました。
Butter Knife / lombok とかを使って、コード量の削減にも努めました。
いろいろとチャレンジ出来たので、楽しかったです。
要件がころころ変わるのは辛かったですが。
個人
2013年9月にデベロッパー登録し、1月にようやくリリースしました。
- Raspberry Pi / IRKit買った(5月)
IoTのきっかけとして、買ってみました。 自宅の電気・エアコンなどを操作したかったのですが、めんどくさくなって放置してます。
- Androidアプリ SlideViewerリリース(9月)
Speaker DeckのAndroidクライアントが無かった and Web画面が見づらかったので、作りました。 スクレイピングの勉強になったし、自分ではいい感じに使っているんですが、DL数は伸びないですね。。
- Androidアプリ TetherSettingの収益アップ(9月)
全画面広告を導入したことにより、1日当たり100円前後だったのが、1日当たり800円前後ぐらいになった。
2015年にやること・目標
仕事
- 改善業務
1月は半分ぐらい引き継ぎに割かれるけど、それ以降は基本的に案件には入らず、引いた立場となります。
具体的に何をやるかは、まだ検討段階ですが、情報共有を推進したり、CI / CDを導入したりしていく予定です。
この活動によって、品質が上がったり、稼働時間を減らしていければと思います。
- リモートワーク
1月下旬か、2月の頭ぐらいに富山に戻ります。
(飲み会の席で社長もちらっと言ってたし、いいよね?酔ってて、正確には覚えてないけど。)
在宅での作業になります。
ちゃんとバリューを出せるかなど、不安満載ですが、頑張っていこうと思います。
ちなみに、「結婚すんの?」と言われますが、そうでもないっす。
個人
- 各アプリの改善
Android版の詰め共円は目下改修中ですが、それ以外のアプリも、CIを導入したり、Material Designに変更したりしていこうと思います。
- 本を読む
元々長いこと関東に住む予定も無かったので、物理的な本はあんまり買わないようにしていました。
電子書籍はそれなりに買って読んでたんですが、物理本は敬遠してました。
がっつり本棚買って、本も買って読もうと思います。
本来の言葉の定義とはちょっと違う気もしますが、新しい部屋にいろんなデバイスを導入したいと思います。
IRKitとかはあるので、あとは hue とか買ってみようかなーと思ってます。
- 健康に気をつける
在宅での作業になると、何も考えないと、日に100歩も歩かない気がします。
27才になるので、多少は気を使った方がいいかなーと。
具体的に何するかは決めてないですが。。。
- アニメ見る本数を減らす
毎クール20〜30本ぐらい見てたっぽいです。
毎日1時間ぐらいをアニメに費やしていたようです。
無駄とまでは言いたくないですが、もっとやるべきこと・やりたいことがあるはずです。
減らしていこうと思います。
- 文章を書く技術をつける
前から気づいてたけど、文章作成能力が弱い。
読みやすい技術ブログが、なぜ読みやすいかを分析して、自分の力に変えていこうと思います。
ブログとか、社内の情報共有で、その成果を発揮したいです。
雑感
2014年は、結果、そんなに大きなイベントは無かったような感じです。
ただ、後半からは2015年に向けていろいろと動けた気がします。
このまま、いろいろと進めていければと思います。
個人目標はいっぱい書きましたが、それなりに達成したいです。
Travis CI と Slackを連携させる
Referencing DOM nodes in Angular expressions is disallowed! が出たとき
Angularのイベントの最後にDOM操作を行っていました。
$scope.send = () -> $("#dialog")?.hide()
ng-click
で上記の関数を呼び出していました。
そこで、タイトルのエラーが表示されてしまいました。
$scope.send = () -> $("#dialog")?.hide() ''
これで解決。 DOMをreturnしたらいけないっぽい。
参考:
Codeigniterでヘッダの扱いでハマった話
仕事でネイティブアプリと通信するAPIのサーバサイド実装をしています。
アプリの強制アップデート機能を実装するために、HTTPヘッダに"App-Version"という項目を追加して、Inputクラスのget_request_headerで取得しようとしました。 最初にやってみた実装は下記の通り。
$this->input->get_request_header('App-Version');
で、取得できませんでした。
とりあえず、出力させてみようということで、下記を実行してみました。
log_message('debug', var_export($this->input->request_headers(), true));
で、ログを確認すると、キーがApp-version
になってました。
$this->input->get_request_header('App-version');
にしたら、無事、取得出来ました。
request_headersメソッド内のコメントを見ると、
// take SOME_HEADER and turn it into Some-Header
ってかいてあったから、versionの頭も大文字になるものだとばっかり。。。
CodeIgniterのバージョンは、2.1.4です。
最新のバージョンでどうなってるかはわかんないですが、こうゆうことが、ちらほら出てくるので、CodeIgniterはあんまり好きになれないんですよねー。。。
社内勉強会を開催しました
10/9の20時より、サーバ・インフラ社内勉強会を開催しました。
(自分が面接官をやらないといけなかった関係で、こんな時間になってしまいました)
参加者は下記のような感じ。
- 中堅Android・サーバエンジニア
- 中堅サーバ・インフラエンジニア(鹿児島からリモート!)
- 若手エンジニア
- 若手ビジネスプロデューサー(いわゆる営業)
- 中堅?フロントエンドエンジニア(最後の数分のみ参加)
スライドはこちら。
結構初歩的なことしか喋ってないですが、サーバやインフラのことを理解してない人には勉強になったんじゃないかな、と思います。
中堅の人にはツッコミを入れてもらい、私も勉強になりましたし。
「勉強会開いて下さい!」って言ってきたフロントエンドエンジニアが参加できなかったのは残念でしたがw
鹿児島からも発表してもらって、自分も勉強出来ました。
続くかも、って書いてますが、社外への常駐が増えそうなので、難しいかなーと思います。
まぁ、機会があればまたやってみたいと思います。
SlideViewerをリリースしました
本日、SlideViewerというAndroidアプリをリリースしました。
とりあえず、Speaker Deckのクライアントアプリです。
GitHub にコードは一通り置いてあります。
Speaker Deckのスライドページを開く際に、SlideViewerアプリが選択できます。
APIなどが提供されていなかったので、スクレイピングしています。
そのため、初回の読み込みは遅いのですが、スライド表示中にある程度先読みするため、読んでる間にストレスは溜まりづらいかと思います。
何より、標準ブラウザで見た時は大きさが中途半端になってしまうのが、幅いっぱいに表示されます。
ただ、最低限必要な機能は実装したのでリリースしましたが、もうちょっと改修する予定です。
画面回転に対応できてなかったり、改めて見ると、残念なところが多いですね。。。
で、そこら辺も完了したら、Slide Shareとか、他?も閲覧できるようにしたいと思います。どこまでモチベーションが持つかが勝負ですが。
そもそも、一番の問題は、スクレイピングしていることを怒られないか、という点ですが。
Integerを"=="で比較してはいけない
追記:Javaの話です。
public class Main { public static void main(String args[]) throws Exception { Integer i1 = 1; Integer i2 = get1(); if (i1 == i2) { System.out.println("equal"); } else { System.out.println("not equal!!"); } } public static Integer get1() { // DBとかから取ってきたつもり return new Integer(1); } }
は、"not equal!!"と言われてしまいます。
(ただし、コンパイラや実行環境に依存するかもしれません。)
Integerはプリミティブ型ではないので、==
では、同一のインスタンスかどうかを確認してしまっているんですね。(たぶん
普通、比較といえば、値の同一性を知りたいと思うので、
public class Main { public static void main(String args[]) throws Exception { Integer i1 = 1; Integer i2 = get1(); if (i1.equals(i2)) { // ←ここを変えた System.out.println("equal!!"); } else { System.out.println("not equal!!"); } } public static Integer get1() { // DBとかから取ってきたつもり return new Integer(1); } }
まぁ、こうしますよね。
ただ、上記の場合は i1
がnullの場合はNullPointerExceptionが発生します。当たり前ですね。
なので、 i1
が必ずnullでは無い場合にしか使えないです。
nullの場合、一致とみなすか、不一致とみなすかは文脈によるかと思いますので、割愛します。
org.apache.commons.lang.ObjectUtils.equals
を利用するのも手ですね。
8/10追記 java.util.Objects.equals ってのがJava7からあるみたいです。(コメントで教えていただきました。)
ちゃんと考えれば当たり前なんですが、誰かの書いたコードで、ぼんやり読んでるとハマりますね。(というか、ハマりました。
Travis CIでAndroidアプリをビルドしてDeployGateに置く
継続的インテグレーションをAndroidでもしたい!ということで、
- Travis CI - Free Hosted Continuous Integration Platform for the Open Source Community
- DeployGate - An incredibly easy way to deploy apps in development!
ここらへんを使い、
ということを実現したいと思います。
対象は、現在全リファクタリング中のこちら。
https://github.com/noboru-i/kyouen-android/tree/renew
.travis.yml の設定
language: android env: global: # deploygate - DEPLOYGATE_USER=noboru-i - secure: "SOev0rrhdJ6fp5CkJeQAh6mm6EmmWEWCVrSt7hn3mvjSbaz/yKdmiGsHp8NcTeLZrXuk6ay6mFee3TVqsT17Xn5+cGG5nnWFPqI2Os3AlSWdHkhLrv8f3KdfwJeTiBSymw4TDWSd/kVCB42q51BdnODda+GozCymA6qoZpf/GQs=" # secret_strings.xml - secure: "ZXnouETJ67n/DCjCFPdWoIm3eo0WsYhfuy9Y25IjYn6gij4F8v038bjYr+Z5QBsnLri1mU0QQeNy14cPaaYBoblTsmPm0cZ+Vv0wmYgAkVc2C+E67k/YUAD0puvUzUGsQ1z6N7gQ0tFjL4l4map/4iEkGtney6OYdyuljE75D2g=" - secure: "Sqi+dwZcd6qGpBLYUq+deqQBSX056N0eoQ9RfMjWB7gG/WfQn4XQaTF13jKdqp0MKzRj8P61uunoxZIpHNYNWeqzxfIpXKrzOdGv85r8PnbjDgH87N22ufqwPdbfAVydUEPP8hEEJ5vbCN2Fyoq1CHPNjwBpMIiD27LMVjiytn8=" - secure: "iUO0ldYPT3jYjoRafH0Milc3DNhgqzZQGk7tFkvg7WPF+YPEYDOMjwmhY0kTDjbxU+iqkHE7WOL66MtJSlvTJjNfs2uWqrXrmgMAXLusbRukscJmL2ZwGhNwBi4tOOl4V1FO8NRqYcdRkkHgJRUXyKAafLrdNePVm7uWUwjl2e0=" - secure: "PCeJAQ8/XrDWktlTbKtJLCcjhjOfsw/tcPPCrG1urvQMJrgzi6m6pTWo62RSpWVo1iYePiqvDgPGACrT082vtnoJ7TJ3FZEhty1xsDUhDBJ9qvmHEPpxLrtLGwZ1+doT/yxinQAqqucx8vsFJcTh8zOrGLknwEvqxhNj5HHKzkg=" - secure: "MyGGNdkyv+qEf8yhORcSzjsHbDjT2yILka/aMYgInt0oyF3T6O6JwwRvrXHEulPVHWsWu4LCxX8e3HeyyQ0OkIjc67nwIsajCDwDlVUcnkjqyV3r9xPn0HlltwvS63QuQGln6NQIUBk9nVIuaA+vno7bod1Px0VESu9kDgUiqgI=" notifications: email: false android: components: - build-tools-19.1.0 - android-19 - sysimg-19 - extra-android-support licenses: - android-sdk-license-5be876d5 - '.*intel.+' before_install: - android list sdk --no-ui --all --extended script: - ./gradlew uploadDeployGateDebug
env.globalには下記を記載しています。
作成については、下記のコマンドで。
travis encrypt GCM_SENDER_ID=9999999999999
これを、後述のgradle taskでxmlに書き込みます。
Projectのbuild.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:0.12.+' // deploygate classpath 'com.deploygate:gradle:0.6' } } allprojects { repositories { jcenter() } }
DeployGateのgradle pluginをここで設定しています。
アプリのbuild.gradle
apply plugin: 'com.android.application' apply plugin: 'deploygate' android { // Error:duplicate files during packaging of APK /XXX/app-debug-unaligned.apk 対策 packagingOptions { exclude 'META-INF/license.txt' exclude 'META-INF/notice.txt' } compileSdkVersion 19 buildToolsVersion "19.1.0" defaultConfig { applicationId "hm.orz.chaos114.android.tumekyouen" minSdkVersion 12 targetSdkVersion 19 versionCode 18 versionName "0.10.0" } buildTypes { release { runProguard false // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } lintOptions { abortOnError false } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:support-v4:19.0.+' compile 'com.android.support:appcompat-v7:19.+' // deploygate compile 'com.deploygate:sdk:3.1' } apt { arguments { androidManifestFile variant.processResources.manifestFile resourcePackageName 'hm.orz.chaos114.android.tumekyouen' } } deploygate { userName = "$System.env.DEPLOYGATE_USER" token = "$System.env.DEPLOYGATE_TOKEN" apks { debug { sourceFile = file("${project.buildDir}/outputs/apk/app-debug-unaligned.apk") } } } uploadDeployGateDebug.dependsOn assembleDebug task secretKeyReplace { description 'Replace secret keys from system environment.' doLast { def filePath = "app/src/main/res/values/secret_strings.xml" def br = new BufferedReader(new FileReader(filePath)) def lines = br.readLines() br.close() // key情報の抽出 def secretKeys = new HashSet() def rExpression = /INPUT_YOUR_([A-Z_]+)/ for (String line : lines) { if (line.contains("INPUT_YOUR_")) { def matcher = (line =~ rExpression) secretKeys << matcher[0][1] } } // 文字列の置換 def newLines = new ArrayList<String>() for (String line : lines) { String newLine = line for (String key : secretKeys) { if (!System.getenv()[key]) { continue } newLine = newLine.replace("INPUT_YOUR_" + key, System.getenv()[key]) } newLines << newLine } def pw = new PrintWriter(new BufferedWriter(new FileWriter(filePath))) for (def line : newLines) { pw.println(line) } pw.close() } } preBuild.dependsOn secretKeyReplace
buildToolsVersion は、最新が20.0.0だけど、ymlに書いた android-sdk-license-5be876d5
がまだ対応してないようなので、19.1.0になってます。
deploygateタスクの設定(ユーザ名 / パスワード)は環境変数から取得しています。
環境変数への設定は.travis.ymlに書いてあります。
DEPLOYGATE_TOKEN も、暗号化して書いてあります。
secretKeyReplace taskで、secret_strings.xmlにある、"INPUT_YOUR_XXX"を取得、その"XXX"をキーとして環境変数を取得、replaceして同じファイルを置き換えます。
きっと、もっと良いやり方あると思うんだけど、ググっても出てこなかったので、力技です。
Publicリポジトリにキー情報は置けないけど、Travis CIでapkを作るときには必要。みんなどうやってるんだろう?
まとめ
というわけで、GitにPUSHするとDeployGateでアプリが配布されるところまで出来ました。
Publicリポジトリに置けない認証情報を設定する方法が、あんまりいけてないのはなんとかしたいところ。
あとは、テストコード書いて、リグレッションテストを回していきたいと思います。
Robolectricを使うつもりで書いてるので、まとまったらまた書こうと思います。
CocoaPodsでインストールしたのにヘッダが file not found
何故かpod installしてあるのに、 いろいろな書き方でやってみたけど、どれもヘッダがnot foundになってしまった。
#import "AFNetworking.h" #import <AFNetworking.h> #import "AFHTTPRequestOperationManager.h" #import <AFHTTPRequestOperationManager.h> #import <AFNetworking/AFHTTPRequestOperationManager.h>
よくよく考えると、とりあえずpod installだけしてあって、その機能を使おうとしたのは初めてだった。
いろいろ探してると、
objective c - iOS - Build fails with CocoaPods cannot find header files - Stack Overflow
こんなのを見つけた。
なので、それを設定しようとして、その画面を開いたら、
そんなもん無いんですけどー。。。
で、既にあるプロジェクトファイルといろいろ見比べたけど、それっぽい違いが見つからない。
そもそもどうやったら、ここに表示されるものが出来るのか調べたら、
複数のTarget/Configurationを持つiOSプロジェクトの構成Tips - やらなイカ?
こんなの見つけた。
で、動いているプロジェクトには「Pods.xcconfig」があるのに、今のプロジェクトには無い。
Pods/Pods.xcconfig のものをインポートしているようだったので、同じようにプロジェクトに追加したら動いた!
なんで無くなってたんだろう。。。