2015年01月26日

このエントリーをはてなブックマークに追加

UI経由ではバージョン指定できない(2015/01/26現在)

Jenkinsは、恐らく手頃なCIツールだ。個人的には2年半近く使っている。他のツールと同様に、ある程度使い続けていると、どこか使い辛さを感じ始める。Jenkinsにおける使い辛さの1つは、狙ったバージョンのJenkinsプラグインをインストール出来ない事。通常のJenkinsプラグインインストール手順は、こうだ。

  1. プラグインマネージャhttp://jenkins/pluginManager/からプラグインを検索
  2. 欲しいプラグインを選択
  3. プラグインをダウンロード・インストール
  4. Jenkinsを再起動

この手順には、プラグインのバージョンが登場しない。暗黙のルールとして、最新バージョン(latest)が指定され、プラグインがインストールされて行く。しかも、管理者の意図とは関係のない所で、だ。これは問題を含んでいる。とある日に構築したシステム構築を再現する様な場合は、要件を満たせない。そこをどうにかしたくて、手順を確立させた。こんな手順、本当は無くなって欲しい。

プラグインインストールの裏側を理解する

Plugins - Jenkins - Jenkins Wiki より、

By hand Download Site

Save the downloaded *.hpi/*.jpi file into the $JENKINS_HOME/plugins directory. You will then need to restart Jenkins (many containers let you do this without restarting the container)

http://updates.jenkins-ci.org/download/plugins/からJenkinsプラグインをダウンロード出来る事が分かる。プラグインリポジトリを注意深く調査していると、過去のバージョンもダウンロード出来る事が分かる。wikiの内容と調査結果をまとめると、こうなる。

最新版:

  • http://updates.jenkins-ci.org/latest/${name}.hpi

特定バージョン:

  • http://updates.jenkins-ci.org/download/plugins/${name}/${version}/${name}.hpi

保存先:

  • ${JENKINS_HOME}/plugins/${name}.hpi

反映方法:

  • Jenkins再起動

サービス起動後、プラグインマネージャを確認すると、狙ったバージョンのプラグインがインストールされている事を確認できるはずだ。少なくとも、自分が検証した限りでは、期待通りの結果となっている。

おまけ:プラグイン名とバージョンのペアを管理する

パッケージを1つ1つインストールするのは、実に面倒臭い。プラグインによっては最新版が良い場合もある。それを一括管理する為、自分は下記のようなスクリプトによりシステム構築している。

jenkins-plugin.sh:

#!/bin/bash
#
# requires:
#  bash
#
set -e
set -o pipefail

JENKINS_HOME=${JENKINS_HOME:-/var/lib/jenkins}
base_url=http://updates.jenkins-ci.org

function plugin_list() {
  cat <<_EOS_ | egrep -v '^$|^#'
PrioritySorter 1.3
config-autorefresh-plugin
configurationslicing
config-file-provider
cron_column
downstream-buildview
git        1.4.0
git-client 1.1.1
hipchat 0.1.5
greenballs
managed-scripts 1.1
nested-view
next-executions
parameterized-trigger 2.18
rebuild 1.20
timestamper 1.5.6
token-macro
urltrigger
view-job-filters
_EOS_
}

while read line; do
  set ${line}
  name=${1} version=${2}
  if [[ -z "${version}" ]]; then
    version=latest
  else
    version=download/plugins/${name}/${version}
  fi
  curl -fSkL ${base_url}/${version}/${name}.hpi -o ${JENKINS_HOME}/plugins/${name}.hpi
done < <(plugin_list)

chown -R jenkins:jenkins ${JENKINS_HOME}/plugins

ヒアドキュメント部分が、プラグイン名とバージョンを指定のペアを管理。

  • プラグイン名のみの場合は、最新版(latest)をインストール
  • プラグイン名とバージョン指定している場合は、そのバージョンをインストール

上記ヒアドキュメント部分を説明すると、こうなる。

  • バージョン固定:
    • PrioritySorter 1.3
    • git 1.4.0
    • git-client 1.1.1
    • hipchat 0.1.5
    • managed-scripts 1.1
    • parameterized-trigger 2.18
    • rebuild 1.20
    • timestamper 1.5.6
  • 最新版:
    • config-autorefresh-plugin
    • configurationslicing
    • config-file-provider
    • cron_column
    • downstream-buildview
    • greenballs
    • nested-view
    • next-executions
    • token-macro
    • urltrigger
    • view-job-filters

なお、これは自分が今までに使って来た厳選プラグインでもある。

あとがき

使い辛い所を分かった上で使い続けるJenkinsさんとの生活。もう少し続きそう。




編集
@hansode at 10:30|PermalinkComments(0)TrackBack(0)Jenkins 

2015年01月25日

このエントリーをはてなブックマークに追加

if文を省略可

GitHub API v3をcurlコマンド経由でAPI呼び出しをしていると、Token有無による場合分けが、しばしば必要となる。普段は当たり前の様にbashスクリプトを活用してcurlコマンドオプションを組み立てている。そして、-n-zによる文字列テストによる場合分けをしていた。そう、今までは。

[[ -n "${GITHUB_TOKEN}" ]] && { echo "-H \"Authorization: token ${GITHUB_TOKEN}\""; }

ある日、時々シェルスクリプトを書く@unakatsuoが言う。

文字列展開のうち、+の使い方・使い処が分かった。 echo ${var:+"foo ${var}"} みたいに書くと良い。

存在は知っていたが、使わずに来た。

未開拓のパラメタ展開

man bash(1)より。

   Parameter Expansion

       ${parameter:+word}
              Use Alternate Value.  If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.
  • parameterがnullかunsetの場合は置き換えない
  • そうでない場合は置き換える

これを上手く使うと、if文を省略して書けると言う。先述のコードを、+によるパラメタ展開を使い書き直すと、

before:

[[ -n "${GITHUB_TOKEN}" ]] && { echo "-H \"Authorization: token ${GITHUB_TOKEN}\""; }

after:

echo ${GITHUB_TOKEN:+"-H \"Authorization: token ${GITHUB_TOKEN}\""}

コードが短くなった。

おまけ:test-github-issues.sh

普段使いのスクリプトから一部を抜粋。

#!/bin/bash
#
#
set -e
set -o pipefail

function curl() {
  echo curl "${@}"
}

function github_issues() {
  curl \
   -fsSkL \
   $([[ -n "${GITHUB_TOKEN}" ]] && { echo "-H \"Authorization: token ${GITHUB_TOKEN}\""; } ) \
   "https://api.github.com/repos/${owner}/${repo}/issues"
}

function github_issues2() {
  curl \
   -fsSkL \
   ${GITHUB_TOKEN:+"-H \"Authorization: token ${GITHUB_TOKEN}\""} \
   "https://api.github.com/repos/${owner}/${repo}/issues"
}

owner=github
repo=github

GITHUB_TOKEN=     github_issues
GITHUB_TOKEN=     github_issues2

GITHUB_TOKEN=asdf github_issues
GITHUB_TOKEN=asdf github_issues2

[[ "$(GITHUB_TOKEN=     github_issues)" == "$(GITHUB_TOKEN=     github_issues2)" ]]
echo ${?}
[[ "$(GITHUB_TOKEN=asdf github_issues)" == "$(GITHUB_TOKEN=asdf github_issues2)" ]]
echo ${?}

上記スクリプトを実行すると、こうなる。

$ chmod +x ./test-github-issues.sh
$ ./test-github-issues.sh
curl -fsSkL https://api.github.com/repos/github/github/issues
curl -fsSkL https://api.github.com/repos/github/github/issues
curl -fsSkL -H "Authorization: token asdf" https://api.github.com/repos/github/github/issues
curl -fsSkL -H "Authorization: token asdf" https://api.github.com/repos/github/github/issues
0
0
  • GITHUB_TOKEN あり / なし
  • github_issuesgithub_issues2 による生成文字列

生成された文字列が改良前後で同一かどうかをテストし、同一である事を確認。

あとがき

多用し過ぎると可読性が低下しそうなので、ご利用は計画的に。




編集
@hansode at 17:00|PermalinkComments(0)TrackBack(0)bash 

2015年01月24日

このエントリーをはてなブックマークに追加

新規構築は問題が無い

気にすべきは、マイグレーションが実行されるので、ビルドログが多い環境ほど注意が必要となる事。いつものアップグレード時間よりも長く待たされる事を、承知した上でメンテナンスを行えたなら 、言う事は無い。なお、手元のJenkinsクラスタでは、1.596から1.597へのアップグレードは問題なくマイグレーションが完了した。

ハイライトを追いかける。

Changelog | Jenkins CI より

What's new in 1.597 (2015/01/19)

  • JENKINS_HOME layout change: builds are now keyed by build numbers and not timestamps. See Wiki for details and downgrade. (issue 24380)

JENKINS_HOMEのレイアウトを変更したとの事。

レイアウト変更により、buildIDとbuild時刻の関係が逆転

[#JENKINS-24380] Use build numbers as IDs - Jenkins JIRA より

Before:

% ls -la
total 16
drwxrwxr-x 4 kohsuke kohsuke 4096 Sep 15 17:51 .
drwxrwxr-x 4 kohsuke kohsuke 4096 Sep 15 17:51 ..
lrwxrwxrwx 1 kohsuke kohsuke   19 Apr 18 10:42 1 -> 2014-04-18_10-42-35
lrwxrwxrwx 1 kohsuke kohsuke   19 Sep 15 17:51 2 -> 2014-09-15_17-51-46
drwxrwxr-x 2 kohsuke kohsuke 4096 Apr 18 10:42 2014-04-18_10-42-35
drwxrwxr-x 2 kohsuke kohsuke 4096 Sep 15 17:51 2014-09-15_17-51-46
lrwxrwxrwx 1 kohsuke kohsuke    2 Apr 18 10:39 lastFailedBuild -> -1
lrwxrwxrwx 1 kohsuke kohsuke    1 Sep 15 17:51 lastStableBuild -> 2
lrwxrwxrwx 1 kohsuke kohsuke    1 Sep 15 17:51 lastSuccessfulBuild -> 2
lrwxrwxrwx 1 kohsuke kohsuke    2 Apr 18 10:39 lastUnstableBuild -> -1
lrwxrwxrwx 1 kohsuke kohsuke    2 Apr 18 10:39 lastUnsuccessfulBuild -> -1

After:

% ls -la
total 16
drwxrwxr-x 4 kohsuke kohsuke 4096 Sep 15 17:52 .
drwxrwxr-x 4 kohsuke kohsuke 4096 Sep 15 17:51 ..
drwxrwxr-x 2 kohsuke kohsuke 4096 Apr 18 10:42 1
drwxrwxr-x 2 kohsuke kohsuke 4096 Sep 15 17:51 2
lrwxrwxrwx 1 kohsuke kohsuke    1 Sep 15 17:52 2014-04-18_10-42-35 -> 1
lrwxrwxrwx 1 kohsuke kohsuke    1 Sep 15 17:52 2014-09-15_17-51-46 -> 2
lrwxrwxrwx 1 kohsuke kohsuke    2 Apr 18 10:39 lastFailedBuild -> -1
lrwxrwxrwx 1 kohsuke kohsuke    1 Sep 15 17:51 lastStableBuild -> 2
lrwxrwxrwx 1 kohsuke kohsuke    1 Sep 15 17:51 lastSuccessfulBuild -> 2
lrwxrwxrwx 1 kohsuke kohsuke    2 Apr 18 10:39 lastUnstableBuild -> -1
lrwxrwxrwx 1 kohsuke kohsuke    2 Apr 18 10:39 lastUnsuccessfulBuild -> -1
  • 以前は、日付が実態で、build番号がsymlink
  • 今後は、日付がsymlinkで、build番号が実態

この仕様変更によるマイグレーション処理が、システムアップグレード時(プロセス起動時)に発生する。今までのbuildログが多く残されていれば多く残されている程、マイグレーションに時間がかかる。

念の為、アップグレード前にJENKINS_HOMEをバックアップしておいた方が良いかも知れない。それと、事前にbuildログをある程度掃除しておいた方が良いかも知れない。

migration進捗は/var/log/jenkins/jenkins.logで確認可能

migration進捗が気になる場合は/var/log/jenkins/jenkins.logtail -fしておくと良い。過去のbuild番号の数だけdoMigrateが記録されて行く。

Jan 24, 2015 4:08:11 PM jenkins.model.RunIdMigrator doMigrate
WARNING: found no build.xml in 2014-03-06_16-55-39
Jan 24, 2015 4:08:11 PM jenkins.model.RunIdMigrator doMigrate
WARNING: found no build.xml in 2014-01-10_16-56-22
Jan 24, 2015 4:08:11 PM jenkins.model.RunIdMigrator doMigrate
WARNING: found no build.xml in 2013-10-23_16-56-23
Jan 24, 2015 4:08:11 PM jenkins.model.RunIdMigrator doMigrate
WARNING: found no build.xml in 2014-06-16_16-56-47
Jan 24, 2015 4:08:11 PM jenkins.model.RunIdMigrator doMigrate
WARNING: found no build.xml in 2013-12-22_16-56-22

おまけ:buildログ定期削除スクリプト

参考までに、自分が使用しているbuildログ定期削除スクリプト。これを日次実行させている。Jenkinsの定期実行ジョブとして。

#!/bin/bash
#
# requires:
#  bash
#
set -e
set -o pipefail

LANG=C
LC_ALL=C

threshold=+$((30 * 2))

function disk_usage() {
  df -h
  df -k
}

disk_usage

for target_dir in /var/lib/jenkins/jobs/*/builds; do
  [[ -d "${target_dir}" ]] || continue
  echo ... ${target_dir}

  while read line; do
    [[ -f "${line}" ]] || continue
    rm ${line}
  done < <(find ${target_dir} -type f -mtime ${threshold})
done

disk_usage
  • threshold=+$((30 * 2))

thresholdで直近60日分を残すように指定している。この文字列は、findコマンドの引数として使用されるので、+に意味があるので、+を決して忘れぬように。

あとがき

Jenkinsコアパッケージアップグレードは、細目に実施した方が良い。




編集
@hansode at 18:00|PermalinkComments(0)TrackBack(0)Jenkins | wakameci

2015年01月06日

このエントリーをはてなブックマークに追加

快適なOpenSSH作業環境を手に入れるまでの道のり

OpenSSHによるリモートログイン対象が多く、整理せざるを得ない状況に追い込まれた所から始まり、改善を重ね、今の所は快適な環境を手に入れた。これまでの記録を、ここにまとめておく。

主な特徴

  • keychainのような機能
    • ssh-agent多重起動防止
    • ssh-addによる複数の秘密鍵登録管理
    • SSH_AUTH_SOCKパス固定化(screen/tmux detach/reattach連携対応用途)
  • keychainよりも軽量
    • 軽量な理由は、keychainよりも処理してる内容が少ないから

背景・経緯

  1. 作業対象が数台だった頃、各サーバに秘密鍵を配置する運用でしのいで来た
    1. ログイン対象数が増え始める
    2. 管理対象キーペア数が増え始め、鍵管理が面倒臭くなる
    3. SSHクライアントとなる作業用ラップトップ数が増え始める
    4. ~/.ssh/をバージョン管理し、ssh_configと秘密鍵を管理
    5. ~/.ssh/をデプロイする所までは解決 (本エントリにおいては省略)
  2. ログイン時のパスフレーズ入力が面倒になり、ssh-agentについて調査・検証を開始
    1. ssh-agentが自動起動するように~/.bashrcを改良
    2. ssh-agent多重起動問題に遭遇
    3. mitchellh謹製bashrc と出会い、コードを拝借
    4. ssh-agent多重起動防止を実装
  3. 複数の秘密鍵を扱いたいが、mitchellh版ではssh-addのデフォルトパスしか扱ってなかった
    1. 複数の秘密鍵を扱えるように改良
  4. リモートログイン先にて新たなssh-agentが起動して来てしまう問題に遭遇
    1. 大元のSSHクライアント環境においては、単一ssh-agentプロセスのみ起動していて問題は無い
    2. しかし、リモートログインすると、リモートログイン先で新たにssh-agentが起動してしまう問題に遭遇
    3. リモートログイン状態かどうかを判定する仕組みを追加
  5. screenでdetachした後、reattachすると、UNIXソケットパスが切り替わってしまう問題に遭遇
    1. ssh-agentscreenの中から使う方法を発見・拝借し、SSH_AUTH_SOCKを固定化
    2. 更にtmux内からもSSH_AUTH_SOCKが固定化されてる事を確認
  6. リモートログイン先がMacOSの場合、SSH_AUTH_SOCK が固定されない問題に遭遇
    1. Yosemiteでの外部からログインしてssh-agentを正しく使う方法を発見・拝借し、SSH_AUTH_SOCK を固定化
  7. 快適なssh生活を手に入れた
  8. 実は、ここまでまとめ来た内容と似たツールとしてkeychainの存在を知る・・・
    1. keychainモードへの切り替えを試みる
    2. プロトタイプ版を作り、使ってみると、起動するまでが遅かった
    3. keychainモードへの切り替えを保留
    4. keychainの機能のうち、ホームディレクトリがNFSマウントされた環境を考慮した仕組みだけは拝借し、機能追加
  9. 2015/01/06現在、似非keychainで快適生活を過ごしている
  10. YosemiteへのSSHログイン後の鍵が期待通りではない事に気付く
    1. 手元の環境に置いてはYosemiteでの外部からログインしてssh-agentを正しく使う方法が不要だったので、修正・削除
  11. 2015/01/08現在、似非keychainで快適生活を過ごしている

対象環境

  • ログインシェルをbashに設定しているUNIXアカウント
  • ログインシェルをzshに設定しているUNIXアカウント

対象者?(自分が置かれた環境とも言う)

  • ログイン元環境が複数台存在する
  • ログイン先環境が複数台存在する
  • 1日にSSH接続する回数が恐らく多い方だ
  • keychainが遅いと感じている

動作確認済み環境

$ bash --version
$ ssh -V
  • Cygwin 1.7 / Windows 8.1
    • GNU bash, version 4.1.17(9)-release (i686-pc-cygwin)
    • OpenSSH_6.7p1, OpenSSL 1.0.1j 15 Oct 2014
  • MacOS 10.10 (Yosemite)
    • GNU bash, version 3.2.53(1)-release (x86_64-apple-darwin14)
    • OpenSSH_6.2p2, OSSLShim 0.9.8r 8 Dec 2011
  • Raspbian 7.6 (Wheezy)
    • GNU bash, version 4.2.37(1)-release (arm-unknown-linux-gnueabihf)
    • OpenSSH_6.0p1 Debian-4+deb7u2, OpenSSL 1.0.1e 11 Feb 2013
  • Fedora release 20 (Heisenbug)
    • GNU bash, version 4.2.53(1)-release
    • OpenSSH_6.4p1, OpenSSL 1.0.1e-fips 11 Feb 2013
  • CentOS-6.6
    • GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
    • OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013

使い方

  1. 【設定】 後述する作業対象ファイルを作成・修正・保存
  2. 【準備】 新規bashプロセスを作成し、ssh-agentssh-addを自動起動させる
  3. 【実行】 ssh -A <remotehost> にてリモートホストにSSH接続

作業対象ファイル

  1. ~/.bashrc or ~/.zshrc - 必須
    • 追記。無い場合は新規作成。
    • SSHクライアントおよび全SSH接続対象に反映
  2. ~/.ssh/agent_keys - 必要に応じて
    • 新規作成 +SSHクライアント環境のみ
~/.bashrc or ~/.zshrc- 必須

~/.zshrcにおいても動作を確認。bash前提で話を進めて行くので、zshの場合はbashzshで読み替えて頂きたい。

SSHクライアント環境および全SSH接続対象の~/.bashrcに追記・反映する必要がある。下記内容を、~/.bashrcに追記。追記場所は行末などで良い。

#-------------------------------------------------------------------------------
# SSH Agent
# + based on https://github.com/mitchellh/dotfiles/blob/master/bashrc#L181-L203
#-------------------------------------------------------------------------------

ssh_env=${HOME}/.ssh/environment.${HOSTNAME}

function start_ssh_agent() {
  # remote?
  [[ -z "${SSH_CLIENT}" ]] || return 0

  ssh-agent | sed 's/^echo/#echo/' > ${ssh_env}
  chmod 0600 ${ssh_env}
  . ${ssh_env} > /dev/null

  local ssh_agent_keys=${HOME}/.ssh/agent_keys

  if [[ -f "${ssh_agent_keys}" ]]; then
    local privkey=
    while read privkey; do
      # expand a file path using "~" or "${HOME}"
      eval privkey=${privkey}
      [[ -f "${privkey}" ]] || continue
      ssh-add ${privkey}
    done < ${ssh_agent_keys}
  else
    ssh-add
  fi
}

# Source SSH agent settings if it is already running, otherwise start
# up the agent proprely.

if [[ -f "${ssh_env}" ]]; then
  . ${ssh_env} > /dev/null
  ps -p ${SSH_AGENT_PID} > /dev/null || {
    start_ssh_agent
  }
else
  start_ssh_agent
fi

# static ssh agent sock path

ssh_agent_sock=${HOME}/.ssh/agent.sock.${HOSTNAME}

# based on http://www.gcd.org/blog/2006/09/100/
if ! [[ -L "${SSH_AUTH_SOCK}" ]] && [[ -S "${SSH_AUTH_SOCK}" ]]; then
  ln -fs ${SSH_AUTH_SOCK} ${ssh_agent_sock}
  export SSH_AUTH_SOCK=${ssh_agent_sock}
fi
~/.ssh/agent_keys - 必要に応じて作成

このファイルは作成しなくても良い。もしも使う場合、記述例は下記の通り。

~/.ssh/keys/github/hansode
~/.ssh/keys/wakame/deploy

この仕組みが威力を発揮する主な状況は、

  • 扱う秘密鍵が複数存在する時
  • 扱う秘密鍵は単数だが、ssh-addコマンドで追加させたい秘密鍵パスがデフォルト検索パスではなく、別の場所か複数指定したい時

なお、デフォルト検索パスはssh-addmanで述べられている。

man ssh-add より:

 DESCRIPTION
     ssh-add adds private key identities to the authentication agent,
    ssh-agent(1).  When run without arguments, it adds the files
    ~/.ssh/id_rsa, ~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ed25519 and
    ~/.ssh/identity.  After loading a private key, ssh-add will try to load
    corresponding certificate information from the filename obtained by
    appending -cert.pub to the name of the private key file.  Alternative
    file names can be given on the command line.

manに述べられている通り、引数無しssh-addコマンド実行の場合は、下記ファイルが追加対象となる。

  • ~/.ssh/id_rsa
  • ~/.ssh/id_dsa
  • ~/.ssh/id_ecdsa
  • ~/.ssh/id_ed25519
  • ~/.ssh/identity

これらに該当しないファイルパス、または複数ファイルを扱いたい場合、~/.ssh/agent_keysに記述しておくと、秘密鍵を容易に扱えるようになる。例え扱う秘密鍵が単一であり、しかもデフォルト検索対象であったとしても、明示的な宣言により、何を利用しているのかが見えやすいと言うメリットがある。それゆえ、個人的には積極的に利用している。

動作確認: ローカル環境編

前提条件
  • ローカル環境の~/.bashrc 修正が完了している事
確認項目
  1. ssh-agentが自動起動する
  2. ssh-addにより秘密鍵が登録される事
  3. ssh-agentが多重起動しない事
  4. SSH_AUTH_SOCKが固定化される事
確認作業: ssh-agent自動起動、ssh-addによる鍵登録、多重起動防止

bashを起動する。設定が正しければ、ssh-agent起動とssh-addによる複数鍵登録に成功し、下記のような出力が得られる。キーペアにパスフレーズが設定されている場合は、パスフレーズ入力待ちとなる。

localhost$ bash
Identity added: /home/hansode/.ssh/keys/github/hansode (dsa w/o comment)
Identity added: /home/hansode/.ssh/keys/wakame/deploy (rsa w/o comment)

次に、ssh-agentが多重起動しない事を確認する。新たなbash起動前のPIDを確認。

localhost$ echo $$
6796

PID6796である事が分かった。更にbashを起動。

localhost$ bash
localhost$ echo $$
2388

bash起動後、今度は何も出力されていない。そしてPID2388。これにより、別PIDである事が分かる。更にもう1つbashを起動してみる。

localhost$ bash
localhost$ echo $$
3916

PIDssh-agentの起動状況をまとめると、

  1. PID=6796 - ssh-agentが起動
  2. PID=2388 - ssh-agentは起動しない
  3. PID=3916 - ssh-agentは起動しない

整理すると、

  • ssh-agnetが起動してない場合は、ssh-agentを起動し、ssh-addで秘密鍵を登録
  • ssh-agentが起動している場合は、何もしない
  • ssh-agent多重起動を防止
確認作業: SSH_AUTH_SOCK固定化

SSHに関する環境変数を確認。

localhost$ env | sort | egrep ^SSH_
SSH_AGENT_PID=192
SSH_AUTH_SOCK=/home/hansode/.ssh/agent.sock.localhost

この結果から、SSH_AUTH_SOCK~/.ssh/agent.sock.${HOSTNAME}である事が分かる。ファイルパスに${HOSTNAME}を含めている理由は、ホームディレクトリがNFSマウントされた環境においても動作させる為。

~/.ssh/agent.sock.${HOSTNAME}のファイル情報を確認してみると、

localhost$ ls -l ~/.ssh/agent.sock.localhost
lrwxrwxrwx 1 hansode なし 32 Jan  3 21:39 /home/hansode/.ssh/agent.sock.localhost -> /tmp/ssh-3RRm1KL1FZ1A/agent.6700=

SSH_AUTH_SOCKに指定されているファイルは、シンボリックリンクである事が分かる。

シンボリックリンク先は/tmp/ssh-3RRm1KL1FZ1A/agent.6700である事も分かる。/tmp/ssh-3RRm1KL1FZ1A/agent.6700のファイル情報を確認してみると、実態となるUNIXソケットである事が分かる。

localhost$ ls -l /tmp/ssh-3RRm1KL1FZ1A/agent.6700
srw------- 1 hansode なし 0 Jan  3 21:29 /tmp/ssh-3RRm1KL1FZ1A/agent.6700=

整理すると、

  1. SSH_AUTH_SOCK~/.ssh/agent.sock.${HOSTNAME}
  2. ~/.ssh/agent.sock.${HOSTNAME}は、シンボリックリンク
  3. リンク先は/tmp/ssh-3RRm1KL1FZ1A/agent.6700

ssh-agentが改めて起動する場合は、シンボリックリンク情報だけが張り替わり、SSH_AUTH_SOCK=~/.ssh/agent.sock.${HOSTNAME}は固定化・定数化される。

動作確認: リモート環境編

前提条件
  • ローカル環境の~/.bashrc 修正が完了している事
    • ssh-agentが起動してる事
    • リモート環境用キーペアの秘密鍵がssh-addによる登録されてる事
  • リモート環境の~/.bashrc 修正が完了している事
    • リモート環境用キーペアの公開鍵が~/.ssh/authorized_keysに登録されてる事
確認項目
  1. SSH_AUTH_SOCKが固定化される事
確認作業: SSH_AUTH_SOCK固定化

参考までに、ForwardAgent noの場合は、SSH_AUTH_SOCKが存在しない。

localhost$ ssh remotehost
remotehost$ env | sort | egrep ^SSH_
SSH_CLIENT=192.0.2.68 39922 22
SSH_CONNECTION=192.0.2.68 39922 192.0.2.101 22
SSH_TTY=/dev/pts/0

ForwardAgent yes(-Aオプション付き)の場合は、SSH_AUTH_SOCKが設定される。そして、リモート環境においても~/.ssh/agent.sock.remotehostが設定されている事も分かる。

localhost$ ssh -A remotehost
remotehost$ env | sort | egrep ^SSH_
SSH_AUTH_SOCK=/home/hansode/.ssh/agent.sock.remotehost
SSH_CLIENT=121.114.159.68 39934 22
SSH_CONNECTION=192.0.2.68 39922 192.0.2.101 22
SSH_TTY=/dev/pts/0

ローカル環境と同じ様に、リモート環境も~/.ssh/agent.sock.remotehostは、実態ソケットファイルを参照するシンボリックリンクとなっている事が分かる。

remotehost$ ls -l ~/.ssh/agent.sock.remotehost
lrwxrwxrwx 1 hansode hansode 31 Jan  3 22:33 /home/hansode/.ssh/agent.sock.remotehost -> /tmp/ssh-2cwxr7qAo7/agent.30716

動作確認: リモート環境screen連携編

前提条件
  • ローカル環境の~/.bashrc 修正が完了している事
  • リモート環境の~/.bashrc 修正が完了している事
確認項目
  1. SSH_AUTH_SOCK
    1. screenの外から固定化されている事
    2. screenの中から固定化されている事
    3. detach/reattachしたscreenの中からも固定化されている事
確認作業: SSH_AUTH_SOCK固定化

ForwardAgent yes(-Aオプション付き)で対象サーバにSSHログイン。

localhost$ ssh -A remotehost

screen起動前のPIDと環境変数SSH_AUTH_SOCKを確認。

remotehost$ echo $$
27973
remotehost$ printenv SSH_AUTH_SOCK
/home/hansode/.ssh/agent.sock.remotehost

期待通り~/.ssh/agent.sock.${HOSTNAME}が指定されている。

この時のファイルパスが、ローカル環境におけるファイルパスとは違う事に注目したい。リモート環境はリモート環境特有ファイルパスが生成されいてる。

  • localhost: ~/.ssh/agent.sock.localhost
  • remotehost: ~/.ssh/agent.sock.remotehost

これはローカル環境と同様にNFSマウントされたホームディレクトリ環境を考慮した仕組みである。

次にscreenを起動。

remotehost$ screen

screen内のプロセスIDと環境変数SSH_AUTH_SOCKを確認。

remotehost:screen$ echo $$
28303
remotehost:screen$ printenv SSH_AUTH_SOCK
/home/hansode/.ssh/agent.sock.remotehost

期待通り~/.ssh/agent.sock.${HOSTNAME}が指定されている。

次に、detachしreattachする。

remotehost$ screen -r

再度screen内のプロセスIDと環境変数SSH_AUTH_SOCKを確認。

remotehost:screen$ echo $$
28303
remotehost:screen$ printenv SSH_AUTH_SOCK
/home/hansode/.ssh/agent.sock.remotehost

期待通り~/.ssh/agent.sockが指定されている。これにより、detachしたscreen内の作業を後日行う事が可能だ。

余談:Keychain化を試みたが・・・

ある程度の仕組みをまとめ終えてからkeychainの存在を知り、一度はkeychainに乗り換え作業をしてみた。結果は、keychainを使わない事を選択した。理由は、keychain起動速度が遅い事。多機能ゆえに速度が犠牲になっているのだろう。秘密鍵を常時5つ登録している状況においては、特に遅く感じられた。独自実装だけでも機能要件を満たしていたので、敢えてkeychain化を中断した。

個人利用の限りでは、似非keychainで問題は無い。仮に多人数を対象にした鍵管理フローを構築したい場合は、keychain仕様が良いのかも知れない。少なくとも誰か1人が不満を言うまでは。

現バージョンの課題

  • ssh-agent再起動を考慮してない
    • 解決策はssh-agent -kを手動実行し、bashを起動

あとがき

本エントリを書くきっかけとなったのは、身近なメンバーに対して自分のssh-agent・秘密鍵管理術の説明資料が無かった事。彼らに作業改善案を口頭で説明・提案するにしては、伝える量が多く、手頃な説明資料が欲しくなった。そして、今回の末年始休みを活用し、まとめ終えた。

エントリ初版は数時間で書き終えたが、どうしても関連するコードが気になり、整理を開始。そして再検証作業、文書修正・・・。最終的に書き終えるまでにかかったのは、合計6日間。関連物も含め、整理する良い期間となった。

とにかく、手頃な説明資料を手に入れた!喜ばしい。

関連成果物

参考文献

続きを読む


編集
@hansode at 10:30|PermalinkComments(0)TrackBack(0)openssh 

2014年12月20日

このエントリーをはてなブックマークに追加

Wakame-vdc / OpenVNet Advent Calendar 2014 12/20担当 (5回目)

enter image description here

開発の話は、開発担当者にお任せし、自分はCI環境周りの裏側のお話。
書けるネタは多々ある事が悩ましい。今回は、このネタを。

これまでの開発環境の概略

前回 は開発環境の構成履歴に触れた。

env-changelog

コンポーネントから見た構成変化

Wakame-vdcのコンポーネントを大きく2つに分けると、dcmgrとhvaに分けられる。それを踏まえ、変化の経歴を振り返ってみる。

env-changelog2
V0: Hva 1台構成
  • 構成概要
    • 全部入り
    • dcmgrとhvaを、1台の物理上で起動
  • 問題・課題
    • コンポーネント単位の評価・検証を行えない
V1: Dcmgr VM化
  • 構成概要
    • dcmgrとhvaを明確に分離
    • dcmgr用に専用VMを作成
  • 問題・課題
    • 複数ホスト間のセキュリティグループ検証
    • L3越え
V2: Hva複数台構成
  • 構成概要
    • hvaを複数台構成にし、L3越え対応
  • 問題・課題
    • 1拠点内の検証
    • 内外通信の検証を行えない
V3: 2拠点構成
  • 構成概要
    • 複数拠点対応
  • 問題・課題
    • 今の所無し

あとがき

こう言った視点においては、V4が登場する事は無さそうか。敢えて何か定義するならば、V3管理レイヤーだろうか。




編集
@hansode at 10:30|PermalinkComments(0)TrackBack(0)

2014年12月16日

このエントリーをはてなブックマークに追加

Wakame-vdc / OpenVNet Advent Calendar 2014 12/16担当 (4回目)

enter image description here

引き続き、開発の話は、開発担当者にお任せし、自分はCI環境周りのお話。

開発環境構成履歴

主にCI環境周りにおいて改良・改善して来た4世代分の簡単なまとめ。

V0: Real / 〜2012.08
v0
  • 運用状況
    • 新プロジェクトが発足する度に物理購入
    • 1プロジェクトにつき1物理
    • 時には相乗り出来そうなサーバに相乗り
  • 問題・課題
    • 後日使う可能性ががあるので、環境塩漬け
    • 慢性的に環境不足気味
V1: KVM / 2012.09〜2014.03
v1
  • 運用状況
    • ハードウェア依存しない環境から順にKVM化
    • スクラッチビルドスクリプトによる仮想マシンイメージ作成
    • 開発対象は常にビルドスクリプトセット
  • 問題・課題
    • KVM依存環境の試験・検証
V2: Nested KVM / 2014.04〜2014.10
v2
  • 運用状況
    • KVM依存環境の試験・検証
    • 環境クローン化
    • IPアドレス・MACアドレスのレベルまで複製された複数の検証環境
    • 物理ホスト用OSにfedora-20を採用
  • 問題・課題
    • 1物理内に同一Nested KVMクラスタ構築
V3: Nested KVM on LXC / 2014.11〜現在
v3
  • 運用状況
    • 高い集積率
    • Wakame-vdcクラスタとOpenVNetクラスタが1物理に同居
  • 問題・課題
    • 今の所、無し
    • 敢えて挙げるなら、冗長化

あとがき

V4を探す旅に出ます。




編集
@hansode at 10:30|PermalinkComments(0)TrackBack(0)Wakame 

2014年12月13日

このエントリーをはてなブックマークに追加

Wakame-vdc / OpenVNet Advent Calendar 2014 12/13担当 (3回目)

enter image description here

引き続き、開発の話は、開発担当者にお任せし、自分はCI環境周りのお話。

Wakame-vdc/OpenVNetのCI/CDを支えるJenkinsクラスタ

気付いたら結構な大きさに成長していた手元のJenkinsクラスタ。今回はJenkinsクラスタの一部を紹介。

jenkins ci

JenkinsCIクラスターSlaveノード一覧: 全36ノード

2014/12/13時点のSlaveノードをキャプチャしたもの。

ノード  Jenkins

JenkinsCIクラスターの構成図

Slaveノード一覧キャプチャを見る限りでは、フラットな構成に見えている。クラスタ構成を図に書き出してみると、下記の様になる。

wakame-ci-jenkins-blog

※クリックで拡大(少々見づらいので改善予定)

ノードの色の意味

  • 緑: Jenkins-Master
  • 白: Jenkins-Slave
  • 灰: 多段SSH用踏み台

ノードの分類

  • 物理
    • ci01.dh (nested kvm host)
    • ci02.dh (nested kvm host)
    • ci03.dh (nested kvm host)
    • phys023 (nested kvm on lxc host)
    • phys024 (nested kvm on lxc host)
    • phys025 (nested kvm on lxc host)
    • phys026 (nested kvm on lxc host)
    • phys027 (nested kvm on lxc host)
    • opty (踏み台)
  • KVM
    • master
    • kemumaki12 x2
    • kemumaki13 x2
    • vzkemumaki20 x3
    • lxckemumaki21
    • kemu50 (踏み台)
    • kemu51
    • dsv-fgw01 (踏み台)
    • stg-muscle01-01
    • stg-jenkins01-01
  • LXC Container for KVM Host
    • phys024a (nested kvm host)
    • phys024b (nested kvm host)
    • phys025a (nested kvm host)
    • phys026a (nested kvm host)
    • phys026b (nested kvm host)
    • phys026c (nested kvm host)
    • phys027a (nested kvm host)
  • OpenVZ Container
    • ct101 x3
    • ct102 x3
    • ct103 x3
  • LXC Container
    • lxc101
    • lxc102
    • lxc103

使ってるサーバ仮想化技術

これらはWakame-vdcで使っているもので、個人的には使い慣れた技術の一部。時にはJenkinsクラスタで試験運用し、Wakame-vdcへ反映する事もある。

大半が使い捨て環境

仮想化してあるノードに関しては週1程度の周期で入れ替えを実施。
入れ替えタイミングは、

  • JenkinsCIがリリースされた時
  • OpenVZのvkernelがリリースされた時
  • セキュリティパッチ

1人でメンテナンス、作業時間は5分程度。

各種工程をスクリプト化・自動化してるので、一人で面倒見切れる状況。入れ替え作業は、手動実施で、作業時間は5分程度。作業と言っても、入れ替えスクリプトを実行するだけである。簡単な作業なので自動入れ替えすれば良いのだけども、今の所は検討段階。

あとがき

『こんなJenkinsの使い方をしてる人は居ない。』そんな事を何度か言われた事がある。しかも、変態を見るようなに。そんな経緯があり、愛着を込めて『変態Jenkins』と呼んでいる。




編集
@hansode at 10:30|PermalinkComments(0)TrackBack(0)Wakame 

2014年12月09日

このエントリーをはてなブックマークに追加

Wakame-vdc / OpenVNet Advent Calendar 2014 12/09担当 (2回目)

enter image description here

引き続き、開発の話は、開発担当者にお任せし、自分はCI環境周りのお話。

開発者がコミットしてからmasterにmergeされるまでの流れ

略図を書き出してみると、下記の様になる。

wakame-vdc-ci

各工程ごとに簡単な説明

branch base build / spot-build

wakame-vdc-ci


  1. JenkinsUIのbuild用ジョブから、
  2. branch名を指定し、
  3. ビルドボタンを押下

34f9c1e4-4bc7-11e4-8890-77fed9adf628


今の所、この工程は、敢えて手作業。

rpmbuild: kemumaki

wakame-vdc-ci


  • rpmbuild用chroot環境構築
  • wakame-vdcのrpmbuildのspecファイルからrpmをbuild
  • ローカルyumリポジトリを生成
1box: vmapp-vdc-1box

wakame-vdc-ci


  • vmbuilderを使い、
  • KVM用マシンイメージをbuild
  • Wakame-vdcデモ環境構築configセット
smoketesting: mussel

wakame-vdc-ci


  • APIクライアント
  • 正常性確認用シナリオテスト
    • 簡単なシナリオを挙げると、
      • API呼び出しをしてインスタンス作成
      • インスタンス作成後、SSH接続
      • インスタンスを破棄
GitHub Flow 連携

wakame-vdc-ci


  1. PRを作成
  2. CI環境におけるbuild工程の結果が、コメントに反映される
  3. レビュー担当者によるレビュー
  4. Mergeし、PRを閉じる

9310550c-4bc9-11e4-93fb-22c9e36858da


※Merge後は、リリース工程が存在する。今回はdeveloperに関わる範囲のみなので省略。

developerの負担を可能な限り少なく

以上の様に、developerが登場するのは3回のみで、操作対象はGitHub 2回、JenkinsUI 1回。 その他の作業はCI環境が面倒を見る。build工程は人手を介さないので、失敗する時は毎回失敗する。今時点の課題の1つは、結果が出るまでの時間。buildボタンを押してから、1時間半後に結果が出る。build行程を考慮すると、いくつかは妥協が必要。なお、buildが途中で失敗する場合は、失敗した時点で中断する。

CI構築期間の参考に

この仕組みが出来上がるまでに、1人で、1年半。(他作業を掛け持ちしながら)

あとがき

一度動いてしまえば、あとは継続的改善。




編集
@hansode at 10:30|PermalinkComments(0)TrackBack(0)Wakame 

2014年12月06日

このエントリーをはてなブックマークに追加

Wakame-vdc / OpenVNet Advent Calendar 2014 12/06担当 (1回目)

enter image description here

開発の話は、開発担当者にお任せし、自分はCI環境周りのお話。
書けるネタは多々ある事が悩ましい。今回は、このネタを。

開発環境におけるアカウント管理に悩まされて・・・

背景

アカウント管理が煩雑になっていた。

  • 各自が思い思いのタイミングで作成
  • SSHの認証方式が、パスワード認証だったり、公開鍵認証だったり
  • 各サーバによって、個人のユーザー名が異なる場合も

課題整理してみると・・

  • UNIXユーザー名
    • 作成時に悩みたくない
    • 開発機においては統一したい
  • SSHの認証方式
    • パスワード認証は不可
    • 公開鍵認証のみ

全員がGitHubにアカウントを持ってるので、GitHubベースで揃えられないものか・・・?

github


アカウント管理整理へ
  • 開発機のユーザー名?
    • 全員がGitHubにアカウントを持っている
    • GitHubにおけるユーザー名を使う
  • 公開鍵管理?
    • GitHubにはSSH公開鍵用APIの口があり、ユーザーの毎公開鍵を取得可能
    • 各自から公開鍵を貰う必要が無い
    • 公開鍵入れ替えは、ローカルの公開鍵ファイルを上書き
  • sudoers権限?
    • パスワード設定しないので、NOPASSWDを付与

必要なのは、GitHubのユーザー名だけである事が分かった。
手順整理も出来たので、あとはスクリプト化するだけ。

アカウント管理スクリプト作成

期待するスクリプトは、ユーザー名が唯一の引数。

$ sudo ./add-github-user.sh <github user>

仮に hansode を追加する場合は、

$ sudo ./add-github-user.sh hansode

そして作ったのが、下記プロジェクト。

インストール
$ curl -fsSkL https://raw.githubusercontent.com/hansode/add-github-user.sh/master/add-github-user.sh -o add-github-user.sh
$ chmod +x add-github-user.sh
実行例
$ sudo ./add-github-user.sh hansode
+ [[ -z hansode ]]
++ tr A-Z a-z
+ declare devel_user=hansode
+ declare devel_group=hansode
+ declare devel_home=/home/hansode
+ getent group hansode
+ groupadd hansode
+ getent passwd hansode
+ useradd -g hansode -d /home/hansode -s /bin/bash -m hansode
+ [[ -f /etc/sudoers ]]
+ egrep '^hansode' /etc/sudoers -q
+ echo 'hansode ALL=(ALL) NOPASSWD: ALL'
+ su - hansode -c '/bin/bash -ex'
+ egrep -w '^umask 022' -q /home/hansode/.bashrc
+ echo 'umask 022'
+ su - hansode -c '/bin/bash -ex'
+ mkdir -p -m 700 /home/hansode/.ssh
+ curl -fsSkL https://github.com/hansode.keys -o /home/hansode/.ssh/authorized_keys

あとはこのスクリプトを使い、開発機ごとに必要なアカウントを作成するのみ。

導入後

  • 誰のモノか分からないアカウントが無くなった
  • 構築後は対象サーバのIPアドレスを教えるだけ
  • 環境構築スクリプトからアカウント作成までワンストップ

あとがき

開発者全員がGitHubアカウントを持っているからこそ可能な事。




編集
@hansode at 11:30|PermalinkComments(0)TrackBack(0)Wakame 

2014年02月26日

このエントリーをはてなブックマークに追加

実は初のVagrant Boxエントリ

logo_vagrant-81478652

Vagrant Box生活してる人にだけ伝わればよい。そんな内容。更に限定すると、Vagrant/VirtualBoxの組み合せで生活をしていて、vagrant packagePackerを使わずにVagrant Boxをbuildするような内容の濃い生活をしてる人。

検証環境
  • Windows 8.1
  • Vagrant 1.4.3
  • VirtualBox 4.3.6 r91406
設定項目(VirtualBox)
  • Serial Port: 1つ有効化
/var/log/messagesに出続けるメッセージ

余りにも最小設定・最小構成すぎて、syslogにガンガン書き込まれていた。

このメッセージが出てる原因は、/dev/ttyS0は存在するけども、デバイスとして認識されてない事。VMの構成要素にシリアルポートを追加し忘れていた。

box.ovfを修正

box名によってbox.ovfのファイルパスは異なる。

  • ~/.vagrant.d/boxes/${name}/virtualbox/box.ovf
修正前
修正後: slot="0"enabled="true"

vagrant reloadvagrant upによりシリアルポートが1つ追加された構成でVMが起動する。

あとがき

本エントリではbox.ovfによる修正を行ったけども、Vagrantfileから有効化・無効化する方法もある。その場合は、VBoxManagemodifyvmコマンドに指定するオプションを知っている必要がある。最終的には、VagrantBoxVagrantfile、どちらで指定するのかなどプロジェクト単位における構成管理方針次第か。provider固有設定する必要がある限りは、存在し続ける悩ましい課題の1つ。

参考文献



編集
@hansode at 15:30|PermalinkComments(0)TrackBack(0)Vagrant