pospomeのサーバサイドアーキテクチャ(PDF版)を読み終わりました
pospomeのサーバサイドアーキテクチャ(PDF版)を一通り読み終えたので書評です。
pospomeのサーバサイドアーキテクチャ(PDF版) - pospomeの本屋さん - BOOTH(同人誌通販・ダウンロード)
評価
★★★★★★★★★☆(9/10)
評価の目安はこちら
オススメできる人
- サーバサイドエンジニア
クライアントサイドでもレイヤ周りの話は考えると思うので、
クライアントサイドエンジニアの人でも参考になる内容だと思います。
オススメできない人
- インフラエンジニア
書籍自体はWebアプリケーションアーキテクチャを範囲にしているので、
インフラエンジニアの人にはお勧めできないかもしれません。
感想
世の中でよく出てくるレイヤパターンごとの概要とそれぞれのメリット/デメリットについての説明から始まり、
実際のプロジェクトではどうやって適用していくべきかを
Goのサンプルプログラムをみながら学べる書籍です。
サンプルはGoですが、Goにしか適用できない内容はなかったです。
レイヤパターンについてはWeb記事で説明されることは多いです。
ただ、この書籍ではメリット/デメリットが書かれているので、
それぞれのパターンがどういう時に適用しやすいのかを考えながら読むことができました。
レイヤパターンも適材適所でカスタマイズして使うべきだなと普段から思っていて、
この書籍はその道標として使えそうな気がします。
パッケージ構成についても非常に参考になる内容でした。
パッケージ構成でもしっかりとメリット/デメリットが書かれています。
また、デメリットをどうやって改善していくのかというのもの書かれていてとても参考になりました。
サーバサイドのアプリケーションを作るエンジニアには一読の価値がある書籍だと思いました。
進化的アーキテクチャを読み終わりました
SystemdのCapabilityBoundingSet/AmbientCapabilitiesの挙動
SystemdのCapabilityを調べた時の雑多なメモです。
メモなので結論とかオチとかは全くないです。
更新履歴
2018-10-28 CapInh/CapPrm/CapEff/CapBnd/CapAmbについて調べた内容を追記。
概要
SystemdのserviceファイルにCapabilityBoundingSet/AmbientCapabilitiesをつけた時とそうでない時の
/proc/${pid}/status
の中身の違いを調べてみました。
対象のサービスは8080ポートで起動し、ユーザは一般ユーザで起動しています。
CapabilityBoundingSetとAmbientCapabilitiesの違いってなんだ?
っていうのが気になって調べてみました。
参考サイト
- Linux Capability - ケーパビリティについての整理 - ローファイ日記
- 明日使えない Linux の capabilities の話 - @nojima's blog
- capabilities(7) - Linux manual page
Serviceファイル
実際のサービスファイルは下記のような感じです。
[Unit] Description=Go Crud Application After=network.target After=local-fs.target [Install] WantedBy = multi-user.target [Service] ExecStart=/usr/lib/go-crud/crud -c=/usr/lib/go-crud/conf -s=/usr/lib/go-crud/static/ -p=8080 User=app
CapabilityBoundingSetありの場合は下記を追加します。
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilitiesありの場合は下記を追加します。
AmbientCapabilities=CAP_NET_BIND_SERVICE
実行結果
それぞれの/proc/${pid}/status
の中身です。
[Capabilityなし]
CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000001fffffffff CapAmb: 0000000000000000
[CapabilityBoundingSet]
CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000000000000400 CapAmb: 0000000000000000
[AmbientCapabilities]
CapInh: 0000000000000400 CapPrm: 0000000000000400 CapEff: 0000000000000400 CapBnd: 0000001fffffffff CapAmb: 0000000000000400
設定ごとにこの辺が変わるようです。
それぞれの設定値は以下のようです。 (ドキュメントを読んで書いてはいますが正確に把握できていないです。)
CapInh
このプロセスから新たにプロセスを作成する場合に継承されるセキュリティビットのようです。
CapPrm
Permittedなのでこのプロセスに許可されたセキュリティビットです。
CapEff
最終的に有効となったセキュリティビットのです。
対象のケーパビリティのビットが0の場合は権限なしとして扱われるようです。
CapBnd
CapInhとCapEffで設定されたセキュリティビットに対してマスクをかけるセキュリティビットのです。
起動ユーザのCapInh/CapPrmに設定されものからマスクされ、
CapEffにはマスクされた結果が反映されるようです。
CapAmb
特権を持たない一般ユーザに許可を与えるためのセキュリティビットです。
ここの設定値は連鎖してCapInh/CapPrmに設定されるようです。
おまけ
[Capabilityなし、rootユーザ起動]
CapInh: 0000000000000000 CapPrm: 0000001fffffffff CapEff: 0000001fffffffff CapBnd: 0000001fffffffff CapAmb: 0000000000000000
[CapabilityBoundingSet、rootユーザ起動]
audit.logの権限がないと言われてエラー
[AmbientCapabilities、rootユーザ起動]
CapInh: 0000000000000400 CapPrm: 0000001fffffffff CapEff: 0000001fffffffff CapBnd: 0000001fffffffff CapAmb: 0000000000000400
Goならわかるシステムプログラミングを読み終わりました
Goならわかるシステムプログラミングを一通り読み終えたので書評です。
Goならわかるシステムプログラミング(紙書籍) – 技術書出版と販売のラムダノート
評価
★★★★★★★☆☆☆(7/10)
評価の目安はこちら
オススメできる人
- OSやアプリケーションの内部的な動きを知りたい人
オススメできない人
- Go言語を全く触ったことない人
難しい構文は出てこないので最低限A Tour of Goは目を通した方が良いと思います。
感想
OSやアプリケーション内部の動きがわかりやすく説明されているなというのが感想です。
Webアプリケーションを作っているだけだとOS部分はなかなか手が伸びない箇所ですが
パフォーマンスチューニングやバグ解析といった時に必要になると思います。
そういった際に必要になるOS部分についてかなり網羅されていると感じました。
サンプルコードがGo言語なのでGo言語にフォーカスされていますが
他の言語を触っている人も覚えておいた方が良いと思う内容でした。
普段使っている言語ではどのように動いているかを想像しながら読むと良いかもしれません。
日頃出会わない不具合に立ち向かう時のために一冊として、
パフォーマンスチューニングを勉強するための基本的な知識を得るための一冊として
その両方においておすすめです。
Clean Architectureを読み終わりました
Clean Architectureを一通り読み終えたので書評です。
Clean Architecture 達人に学ぶソフトウェアの構造と設計 Robert C.Martin:生活・実用書 | KADOKAWA
評価
★★★★★★★☆☆☆(7/10)
評価の目安はこちら
オススメできる人
- ソフトウェアアーキテクチャに関する勉強をしたい人
- クリーンアーキテクチャパターンの概要をを知りたい人
オススメできない人
- クリーンアーキテクチャパターンをコードレベルで知りたい人
感想
クリーンアーキテクチャパターンについて書かれているのかと思い購入したのですが、
パターン自体の説明については少なかったので想像していたのとは違う内容でした。
ただ、ソフトウェアアーキテクチャに関する概論といった意味で捉えると参考になる内容が多かったと感じました。
プログラミングのパラダイム、設計の原則、アーキテクチャの方針と
ソフトウェアアーキテクチャを考える上で必要なことが書かれているのではないかと思います。
クリーンアーキテクチャパターンのドメイン/ユースケース/コントローラ、ゲートウェイ、プレゼンタという要素については
10章分くらいで説明がされているのでパターン自体の概要を知るためにも良いと思います。
(「10章分くらい」としているのは対象に入るかどうか個人の感覚によるのでおおよそです)
ただ、ユースケースの入出力のアダプタをコードレベルで詳細には説明を行なっていないので、
コードレベルの設計となると自分で実践しながら覚えていくことになると思います。
GoのカバレッジをCoberturaを使ってJenkinsで表示する
Jenkins
でGo
のカバレッジをグラフィカルに出したいなと思い調べてみたら
gocover-cobertura
というライブラリを使うと実現できるということだったのでまとめてみました。
前提
- Go 1.10.3
- Jenkins 2.121.3
- Go plugin 1.2
- Cobertura Plugin 1.12.1
- dep 0.5.0
概要
Cobertura
はJava
用のカバレッジツールなのでGoで使うためには変換が必要になります。
パイプラインスクリプトの大まかな流れとしては下記です。
まずmakeのスクリプト内部でカバープロファイルを取得します。
取得したカバープロファイルをgocover-cobertura
でCobertura
用のXML変換にします。
最後に変換したXMLをCobertura Plugin
でグラフィルカルに表示します。
make
go test
でカバレッジを取得しようとした時にパラメータを指定しないと
テストが実行されたファイルだけが対象となってしまいます。
この状態でカバレッジを集計するとカバーしているパッケージは必ず100%になってしまうため本来欲しいものが取得できません。
-coverpkg
というパラメータを指定するとその対象のディレクトリが全てカバレッジの計算対象になります。
なので今回は-coverpkg
を使って本当に欲しいカバレッジを取得するようにしています。
テスト時のコマンドは下記のようになります。
go test -coverprofile=${カバープロファイル} -coverpkg=${対象ディレクトリ} ${対象ディレクトリ}
実際に実行されるコマンドは下記のようになります。
go test -coverprofile=bin/cover.out -coverpkg=./example/... ./example/...
bin
ディレクトリの下はGit
の管理対象外ディレクトリとしていることを想定しています。
こういうのはどこに置けばいいのかわからなかったのですが他に適切な場所があればそちらに置くのが良いです。
gocover-coberturaでXMLに変換
gocover-cobertura
を使ってカバープロファイルをXMLに変換します。
パイプラインスクリプトでは毎回gocover-cobertura
を取得するようにしています。
stage("Prepare") { steps { sh 'go get -u github.com/t-yuki/gocover-cobertura' } }
make
コマンドで取得したカバープロファイルを読み込ませます。
sh "gocover-cobertura < bin/cover.out > bin/cover.xml"
ここはgocover-cobertura
公式のサンプルコマンドとほぼ同じです。
Coberturaプラグイン
最後にCobertura Plugin
を使ってグラフィルカルに表示します。
cobertura ( autoUpdateHealth: false, autoUpdateStability: false, coberturaReportFile: 'bin/cover.xml', conditionalCoverageTargets: '70, 0, 0', failUnhealthy: false, failUnstable: false, lineCoverageTargets: '80, 0, 0', maxNumberOfBuilds: 0, methodCoverageTargets: '80, 0, 0', onlyStable: false, zoomCoverageChart: false )
coberturaReportFile
に先ほど変換したXMLファイルのパスを指定するだけです。
生成されたXMLの内容
Cobertura
はJava
用のツールであるため変換されたXMLもJava
に則した内容になっています。
Java
はクラスベースなのでカバレッジの取得もクラスがある前提で集計されます。
Go
の場合はクラスがないのでどういう集計をしているのだろうかと思って結果を見てみたところ
1構造体=1クラス、レシーバのない関数は-
というクラスに属するものとして集計しているようです。
これはgocover-cobertura
の仕様のようです。
まとめ
といことでJenkins
でカバレッジを取得できるようになりました。
-coverpkg
の情報をなかなか見つけられずに苦労しましたが
最終的に出来上がったスクリプトでは難しいことは特にしていないと思います。
わかってしまえばお手軽にできるので簡単にカバレッジ取得できますね。
Go/depを使ったJenkinsビルド
GoのソースをJenkinsからでビルドする方法をまとめてみました。
depを使って依存性を解決した上でビルドというのがなかなか見つけられなかったので色々と試行錯誤してみました。
世の中のプロダクト環境ではもっと良い方法があるのかなとは思いますが・・・
前提
- Go 1.10.3
- Jenkins 2.121.3
- Go plugin 1.2
- dep 0.5.0
私がGo初心者なのでGo界隈で常識的なやり方などは一切知りません。
そんなかで試行錯誤したやり方という前提でお読みください。
参考サイト
概要
やりたいこととしてはdepで依存性を解決してビルドなのですが、
同じJenkinsに複数のGoプロジェクトがあっても大丈夫なようにしたい。
というのがやりたないという感じでやっています。
そのため、GoのバージョンとGOPATH
はプロジェクトごとに変えられるようにしています。
勉強用のコードで作ったものはこちらです。
(masterを参照すると将来的に変わりそうなので動いた当時のコミットです)
環境変数
環境変数の設定処理は下記。
environment { PROJECT_NAME="go-crud-practice" TARGET_GO = tool name: 'Go.1.10.3', type: 'go' GOPATH = "${JENKINS_HOME}/workspace/${env.JOB_NAME}/GOPATH" GOBIN = "${GOPATH}/bin" CHECKOUT_DIR = "GOPATH/src/github.com/gloryof/${PROJECT_NAME}" PATH= "$PATH:${GOBIN}:${TARGET_GO}/bin" }
TARGET_GO
はGo pluginから指定したバージョンのGoのパスを参照しています。
GOPATH
にはプロジェクトごとのパスを設定します。
上記で設定した内容をPATH
に指定してビルド時に使えるようにしています。
CHECKOUT_DIR
にはGOPATH
の中のdep準拠のディレクトリに構成になるようなパスを設定します。
このCHECKOUT_DIR
はチェックアウト処理の時に使います。
depのインストール
depはPrepare
ステージというものを作成して毎回インストールしています。
この書き方だとdepのバージョン変わるので指定したバージョンの取り方は調べないと思いつつやってないです・・・
stage("Prepare") { steps { sh 'go get -u github.com/golang/dep/...' } }
チェックアウト
checkout scm
だと指定したパスにチェックアウトする方法を見つけられなかったので、
色々とパラメータを設定して指定したパスにチェックアウトしています。
stage("Checkout") { steps { checkout([ $class: 'GitSCM', branches: [ [name: '*/master'] ], doGenerateSubmoduleConfigurations: false, extensions: [ [$class: 'RelativeTargetDirectory', relativeTargetDir: "${CHECKOUT_DIR}"] ], submoduleCfg: [], userRemoteConfigs: [ [url: 'https://github.com/gloryof/go-crud-practice'] ] ]) } }
extensions
のRelativeTargetDirectory
を使って指定したパスにチェックアウトします。
relativeTargetDir
に先ほどの環境変数で設定したパスを指定します。
Jenkinsのプロジェクト設定
おそらく普通にパイプラインをチェックアウトするでも動くと思いますが、
追加処理のSparse Checkout paths
にパイプラインスクリプトのパスを設定しています。
Sparse Checkout paths
を指定するとパイプライン実行前のチェックアウトは
その指定したパスだけをチェックアウトするようになるのでファイルが少なくなります。
ビルド
あとはビルドでmakeコマンドを実行するだけです。
dirでワーキングディレクトリを変更しないと動きません。
stage('Build') { steps { dir("${CHECKOUT_DIR}") { sh "make" } } }
まとめ
個人的には実戦でも使えるクオリティのスクリプトができてんじゃないかなと思います。
将来的にJenkinsにdepプラグインが出てくればこういうの不要になりそうな気がしますが。