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プラグインが出てくればこういうの不要になりそうな気がしますが。

RDB技術者のためのNoSQLガイドを読み終わりました

RDB技術者のためのNoSQLガイドを一通り読み終えたので書評です。

RDB技術者のためのNoSQLガイド|書籍情報|秀和システム

評価

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

オススメできる人

  • NoSQLにはどのようなものがあるか知りたい人

オススメできない人

  • NoSQLの特定ソフトウェアの詳細を知りたい人

感想

NoSQLをタイプごとにどのようなものか、
メリットが何か、適した場面はどこかなどが説明してあります。
単純な機能だけではなく、性能拡張/高可用/運用と言った非機能面についても説明されています。

私自身はRDB(主にPostgreSQL)がメインだったので、
RDBとNoSQLの対比というのはとても参考になりました。
ただし、この本が執筆されたタイミングが2015年12月ということもあり
現時点でのRDBとNoSQLの対比をすると変わってくるところも存在しそうです。

RDB側しか情報収集していませんがJSON/レプリケーションといったところは
2016年以降でサポートが強くなっていると思うので当時と現時点では状況が異なると思っています。

それでもNoSQLの詳細を知らない私にとっては参考になった一冊でした。

PostgreSQL 10 Administration Cookbookを読み終わりました

PostgreSQL 10 Administration Cookbookを一通り読み終えたので書評です。

PostgreSQL 10 Administration Cookbook | PACKT Books

評価

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

オススメできる人

オススメできない人

  • PostgreSQLを使って開発のみをする人
  • PostgreSQLの公式ドキュメントを読破した人

PostgreSQL公式ドキュメントが充実しているので
公式ドキュメントを読破している人にとっては知っている内容が多いかもしれません。
(そういう人はかなり少ないと思いますが・・・)

感想

PostgreSQLで運用していて発生した問題などに対して
どうすれば解決できるかというレシピ的なものがまとめられています。
運用ししててリファレンス的に使うのがちょうど良さそうだと思いました。

下記のような部分は他の本では書かれていることは少ないと思います。

そういった部分が書かれていたのは個人的に勉強になったなと思います。

実行時間がかかっていてCPUやIOを使いすぎているプロセスの止め方や
巨大なテーブルに対して早くだいたいのレコード数を知るための方法など
結構コアなところも書いてあります。
コアな操作方法を知るためには良い本かなと思いました。