pospomeのサーバサイドアーキテクチャ(PDF版)を読み終わりました

pospomeのサーバサイドアーキテクチャ(PDF版)を一通り読み終えたので書評です。

pospomeのサーバサイドアーキテクチャ(PDF版) - pospomeの本屋さん - BOOTH(同人誌通販・ダウンロード)

評価

★★★★★★★★★☆(9/10)
評価の目安はこちら

オススメできる人

  • サーバサイドエンジニア

クライアントサイドでもレイヤ周りの話は考えると思うので、
クライアントサイドエンジニアの人でも参考になる内容だと思います。

オススメできない人

  • インフラエンジニア

書籍自体はWebアプリケーションアーキテクチャを範囲にしているので、
インフラエンジニアの人にはお勧めできないかもしれません。

感想

世の中でよく出てくるレイヤパターンごとの概要とそれぞれのメリット/デメリットについての説明から始まり、
実際のプロジェクトではどうやって適用していくべきかを
Goのサンプルプログラムをみながら学べる書籍です。
サンプルはGoですが、Goにしか適用できない内容はなかったです。

レイヤパターンについてはWeb記事で説明されることは多いです。
ただ、この書籍ではメリット/デメリットが書かれているので、
それぞれのパターンがどういう時に適用しやすいのかを考えながら読むことができました。
レイヤパターンも適材適所でカスタマイズして使うべきだなと普段から思っていて、
この書籍はその道標として使えそうな気がします。

パッケージ構成についても非常に参考になる内容でした。
パッケージ構成でもしっかりとメリット/デメリットが書かれています。
また、デメリットをどうやって改善していくのかというのもの書かれていてとても参考になりました。

サーバサイドのアプリケーションを作るエンジニアには一読の価値がある書籍だと思いました。

進化的アーキテクチャを読み終わりました

進化的アーキテクチャを一通り読み終えたので書評です。

O'Reilly Japan - 進化的アーキテクチャ

評価

★★★★★☆☆☆☆☆(5/10)
評価の目安はこちら

オススメできる人

オススメできない人

感想

この書籍に書かれているのは下記のような内容でした。

書いてある内容自体は参考になるなとは感じたものの
実際のどう行動に移せばいいのかと言うのがあんまりイメージできませんでした。
あまり私がこの書籍の内容を把握できていないためかもしれません・・・

SystemdのCapabilityBoundingSet/AmbientCapabilitiesの挙動

SystemdのCapabilityを調べた時の雑多なメモです。
メモなので結論とかオチとかは全くないです。

更新履歴

2018-10-28 CapInh/CapPrm/CapEff/CapBnd/CapAmbについて調べた内容を追記。

概要

SystemdのserviceファイルにCapabilityBoundingSet/AmbientCapabilitiesをつけた時とそうでない時の
/proc/${pid}/statusの中身の違いを調べてみました。
対象のサービスは8080ポートで起動し、ユーザは一般ユーザで起動しています。

CapabilityBoundingSetとAmbientCapabilitiesの違いってなんだ?
っていうのが気になって調べてみました。

参考サイト

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で表示する

JenkinsGoカバレッジをグラフィカルに出したいなと思い調べてみたら
gocover-coberturaというライブラリを使うと実現できるということだったのでまとめてみました。

前提

  • Go 1.10.3
  • Jenkins 2.121.3
    • Go plugin 1.2
    • Cobertura Plugin 1.12.1
  • dep 0.5.0

概要

CoberturaJava用のカバレッジツールなのでGoで使うためには変換が必要になります。
パイプラインスクリプトの大まかな流れとしては下記です。

まずmakeのスクリプト内部でカバープロファイルを取得します。
取得したカバープロファイルをgocover-coberturaCobertura用のXML変換にします。
最後に変換したXMLCobertura 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の内容

CoberturaJava用のツールであるため変換されたXMLJavaに則した内容になっています。
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のインストール

depPrepareステージというものを作成して毎回インストールしています。
この書き方だと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']
            ]
        ])
    }
}

extensionsRelativeTargetDirectoryを使って指定したパスにチェックアウトします。
relativeTargetDirに先ほどの環境変数で設定したパスを指定します。

Jenkinsのプロジェクト設定

おそらく普通にパイプラインをチェックアウトするでも動くと思いますが、
追加処理のSparse Checkout pathsにパイプラインスクリプトのパスを設定しています。

Sparse Checkout pathsを指定するとパイプライン実行前のチェックアウトは
その指定したパスだけをチェックアウトするようになるのでファイルが少なくなります。

ビルド

あとはビルドでmakeコマンドを実行するだけです。
dirでワーキングディレクトリを変更しないと動きません。

stage('Build') {
    steps {
        dir("${CHECKOUT_DIR}") {
            sh "make"
        }    
    }
}

まとめ

個人的には実戦でも使えるクオリティのスクリプトができてんじゃないかなと思います。
将来的にJenkinsにdepプラグインが出てくればこういうの不要になりそうな気がしますが。