AWS CodePipelineからCodeBuildを呼んでlambdaで古いAMIを消すといい感じになる
前回の続き
AWSでAMIの作成をCodeBuildを使って自動化したけど、CodeBuildが動く部分も自動化したいので、Githubに置いてあるリポジトリのmasterにマージされたタイミングで自動的にAMIが作られるといい感じなんじゃないかと思って、「これくらい簡単にできるっしょ」ってやろうとしたらCodeBuildのトリガーなんてものはないと気づいてAWSめんどいってなったので、めんどい部分を書いておきます。
これ作ってから言うのもアレなんですが、CodePipelineはAWSコンソールから操作する分にはある程度自動化されていて便利な反面、 自前でAMI周りの権限をうまくつけるのは結構面倒なので、terraformとかでCodePipeline/CodeBuild/Lambda/CloudWatchLogs/IAM/S3まわりを一気に設定するのは骨が折れるなあという感想です。
まあ、やろうと思えばできます。ただただ面倒です。なんとかならんのか。
で、本題なんですが、CodePipelineっていうのはCIツール的なやつで、CodeBuildがビルド周りしか担当しないのに対して、CodePipelineはソースの取得、ビルドタスクの実行、ビルド後のタスクなどなど、パイプラインの名の通り色々なタスクをルールに従って処理してくれるやつです。
ビルドの並列化などもできるので、CodeBuildだけで足りないところをいい感じに補ってくれるやつと捉えておくといいかもしれません。
CodePipelineのソースにgithubのリポジトリを指定して、masterブランチを監視しておけば、Pull Request単位でレビューをしてmasterにマージされたタイミングで自動的にCodeBuildを走らせるなんてことが簡単にできます。
便利ですね。
流れとしては
- githubのブランチを監視、変更があればソースで取り込む
- CodeBuildでAMIを生成
- Lambdaで古いAMIを削除
という感じになります。
CodePipeline
CodePipeline自体はUIをみたらなんとなく使い方はわかるくらい簡単なので、特に説明はしないのですが、いくつか気になったところだけ補足します。
ソースはアーティファクトの出力が必要
ソースフェーズで取り込んだgithubのリポジトリをCodeBuildに渡す際にアーティファクトという形でs3を経由する必要があります。
まあ、ソースなんでそのソースはs3に置くでしょという感じな気もするのですが、一時的にs3に置かれるのはちょっと面倒だなあという感想もあります。
なんか、噂によるとパーミッション周りが消えるとかいう話もあるし、ソースじゃなくて単なるトリガーみたいなのをつくれないのかなあという気持ちはあります。
ここはあんまり気にせずいきましょう。必要な権限があればCodeBuildのprebuildとかでつければいいかなという感想です。
タイムアウト時間には余裕を持っておく
CodeBuildもLambdaもですが、意外にも時間がかかることがあるのでタイムアウト時間が短すぎるとエラー扱いになります。
CodeBuildは初回実行時におおよその時間を割り出しておくと良いでしょう。LambdaはAMI削除程度なら15秒もあれば十分かなという程度です。(実際には2秒程度で終わる)
LambdaからCodePipelineのタスクが成功したかどうかは自分で報告する必要がある
地味にハマった問題で、タスク呼び出しで呼んだLambdaが成功したかどうかはLambdaでCodePipelineに通知する必要があります。
そうしないと、たとえLambdaが正常終了したとしてもタイムアウトまで待った上で失敗扱いになるので、見栄え上よくないです。
これはテンプレート的に成功の場合は通知処理を書いておけばまあ問題にはならないでしょう。
Lambdaで古いAMIを削除する
まあ、消しましょう。Jenkinsのように古いビルドとアーティファクトを消すものはないので自前で作る必要があります。面倒ですね。
Lambdaなので、Pythonでサクッと実行します。itemgetter
あたりが知らなかったので勉強になりましたね。
images_limit
とかは適当にいじってやるといいと思います。ec2のAPIを呼ぶのでこのLambdaにはEC2の操作権限をつけないといけません。
あと、上で書いたCodepipelineへの通知は code_pipeline.put_job_success_result(jobId=event['CodePipeline.job']['id'])
のところになります。
もうなんかとりあえず最後にこれを置いておくかという感じですね。
終わりに
とりあえず、AMI作成はこれで自動化できるようになりました。
あとは本投入周りのことは考える必要がありますが、まあその辺がインフラエンジニアの腕の見せどころでしょう。
正直この辺はハンコなのでインフラエンジニアは隠居していたいところなのですが、まあサービスしておきましょう。
はー、こんなことより早くアプリケーション側から呼ばれているMySQLのめっちゃ遅いクエリ消さないとなー!!!
Terraformのcodebuild_projectでParameter Storeがサポートされてない件、普通にissueとPull Requestが出ていたけど、テスト周りでゴニョゴニョしてる感じっぽい。しかもここ最近触られててタイムリー
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月23日
あ、書くの忘れてたんですが、terraformだと今のところCodeBuildの環境変数設定でParameter Storeを指定することができないので、CodeBuildのタスク内で秘密情報はSSMから取ってくる必要があります。
まあそのうち改善しそうですが、具体的にはansible-vaultのパスワードみたいなのは自分で取ってくる必要があるという感じです。頑張って下さい。
なんか雑にginとGORMでWebAPIを書き始めたけど意外といい感じに動きそうな感じになってきた
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月22日
最近暇すぎてGolangを勉強がてら書いてます。
本当はGoroutineを使った並列処理とかそういうのを書きたいんですが、ベンチマーカーくらいしかそんな用途なさそう。
だいたい速度面で困ってないし。
MySQLくん、10万程度のrows_examineでも重いことに気づかれないので優秀なのかもしれない(秒で治せるんだけどな
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月22日
次回はこの辺書くかなという感じです。世界を笑顔に。
AWS CodeBuild と packer と ansible でプロビジョニング済みのAMIを自動生成する
AMI生成部分を自動化できたので、ちょっとだけまとめておく。
CodeBuild
- AWSのDockerで動くCIツール。
- CodeBuildの名前の通り、ソースコードをビルドする環境を簡単に作れることをウリにしている
- CircleCIなどのサービスでビルドしたり、Jenkinsを自前で用意するのと比較してそれほど違いはない
- 料金はビルド時間ごとの課金
- 一応無料枠もある
Packer
Ansible
参考ソース
AWSのブログにCodeBuildとPackerを使ったAMIビルダーの構築方法がある。
他にはクラスメソッドさんのブログにAnsibleとPackerの連携周りがある。
- AWS CodeBuild と HashiCorp Packer を用いた AMI ビルダーの構築方法
- Packer+AnsibleによるAMIの作成
- Packer 0.9の新機能 リモートからのAnsible Provisionerが追加されました
この辺りを読めばなんとなく作り方のイメージはできるようになるが、いくつかハマった点があるので補足としてまとめておく。
このリンクだけで十分な人はここから先は読まなくてもOKです。
大まかな流れ
- Ansibleのplaybookはgithubで管理しておく
- CodeBuildでビルド用のDockerを起動、事前のセットアップを行う
- ansible-vaultで使うパスワードをKMSから取ってくる
- 平文を嫌う場合、KMSに登録しておき、環境変数にセットする方法が使える
- packer build でAMIを生成する
AWSのブログと違う点
- Packer 1.2.1
- ansible provisionerを使うため、Docker環境へAnsibleのインストールする
- packerがIAM Roleを扱えるようになったため、クレデンシャルの生成は不要になった
EC2 IAMロールがなんか使えないの謎だから後で調べておくか..
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月15日
- 環境変数 USER を設定する
クラスメソッドさんのPacker+AnsibleによるAMIの作成と違う点
- アクセスキーはIAM Roleを使うので変数を使わない
- ansible-localではなくansibleを使う
- ansibleのインストールは
buildspec.yml
で行う
クラスメソッドさんのPacker 0.9の新機能 リモートからのAnsible Provisionerが追加されましたと違う点
- vaultファイルの管理をする
本題
CodeBuildとPackerを使うため、それぞれのための設定ファイルを用意する。
CodeBuildが buildspec.yml
で Packer は任意の名前のJSON。
buildspec.yml
--- version: 0.2 phases: pre_build: commands: - echo 'Install Packer 1.2.1' - curl -qL -o packer.zip https://releases.hashicorp.com/packer/1.2.1/packer_1.2.1_linux_amd64.zip && unzip packer.zip - echo 'Install Ansible' - apt-get update -y - apt-get install -y software-properties-common - apt-add-repository ppa:ansible/ansible - apt-get update -y - apt-get install -y ansible - echo 'Validate packer json' - ./packer validate packer_ec2.json build: commands: - aws configure set region $AWS_REGION - echo "$ansible_vault_pass" > vault_password_file - echo 'Build AMI' - ./packer build packer_ec2.json post_build: commands: - echo "Build finished `date`"
packer_ec2.json
{ "variables":{ "vault_path": "vault_password_file" }, "builders": [{ "type": "amazon-ebs", "region": "ap-northeast-1", "source_ami": "ami-XXXXXX", "instance_type": "t2.micro", "ssh_username": "root", "ssh_timeout": "5m", "ami_name": "packer_{{ timestamp }}" }], "provisioners": [{ "type" : "ansible", "extra_arguments": "--vault-password-file={{user `vault_path`}}", "playbook_file" : "playbook.yml", "groups" : ["aws", "webserver"] }] }
groups
を配列で渡すと inventory file で複数のグループに属した場合と同じ扱いになる。
これは group_vars
などで設定を切り替える必要がある場合に便利。
vaultファイルは buildspec.yml
で出力したパスを extra_arguments
を使ってそのまま渡している。
IAM Role
XXXXXXXX にはアカウントIDを入れる
以下のポリシーを作成し、CodeBuildで使うIAM Roleにアタッチする。(インラインでも構わない)
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Action": [ "ssm:GetParameters" ], "Resource": [ "arn:aws:ssm:ap-northeast-1:XXXXXXXX:parameter/ansible-vault-pass" ] }, { "Sid": "", "Effect": "Allow", "Action": [ "kms:Decrypt" ], "Resource": [ "arn:aws:kms:ap-northeast-1:XXXXXXXX:key/alias/aws/ss" ] } ] }
KMSからデータを取ってくるために必要。名前は適宜設定すること。
終わりに
いくつかハマりポイントはあったが、これでAMIをCodeBuildで自動的に作れるようになった。
あとはgithubのMergeにHookするとかすれば自動でAMIがどんどん作られていくので便利。
ただ、古いのを消さないと溜まり続けて課金がすごいことになりそう。大変ですね。
packer ansible provisioning 謎のソリューションによっていい感じにAMIが出来上がるんだけど、inventoryファイルとかが自動生成されてるっぽい。リモート側へはSSHのトンネリングかなこれは、イケてる振る舞いしてるけど裏側は結構頑張ってる
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月15日
ついでにこれをCodeBuildに乗せたら失職チャンスでは…(人がいなくても勝手にAMIが生産されていく
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月15日
AWS CodeBuildでPackerを使ってAnsibleのプロビジョニング走らせるところまではできたけど、これAutoScalingと組み合わせるの難しくない?みんなどうやってやってるんだ…????
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月16日
現場からは以上です
AWSの管理をterraformとroadworkerにした
Ansibleのcloud_moduleで大量に書かれたplaybookをterraformに少しずつ移して、 Route53の管理だけをroadworkerに移してみたのですが、 今のところうまくいっているようなので紹介しておきます。
terraform
HashiCorpのGoで書かれたオーケストレーションツール。
各OS、ディストリビューションに合わせた実行可能ファイルが配布されているのでインストールはとても簡単。 インストール方法で悩むチームでも導入の敷居は低いだろうと思う。というかよろしく入れた。
同種のツールとしてはcloudformationがあるが、terraformはGCPなどにも対応している。
設定ファイルはクラウド側の事情に引っ張られやすいため、EC2の設定をGCPに使うということはもちろんできないが、 管理方法などは共通化できる面もある。
ドキュメントはかなりまとまっていてやりたいことに対して設定の例が乗っていることが多い。 多少学習コストはあるが比較的低いと言える。
設定ファイル
terraformの設定ファイルは *.tf
でディレクトリに任意の名前でおいて良い。
terraformの特徴の一つがこの設定ファイルの読み込み方法で、ディレクトリ内のすべての *.tf
が読み込まれて評価される。
具体的に言えば、 s3.tf
や rds.tf
のようにファイルを分割しても 「s3.tf
のみ適用する」ということはできない。
触ったことがないと戸惑うポイントになるが、このルールは「ちゃんと設定を書けば、結果的に個別の適用をする必要は無くなる」ためむしろ楽になる。
terraformの設定はHCLで書く。HCLとは「HashiCorp Configration language」である。
まあ名前の通りなので、特に気にせずこういう感じで書くとだけ思えばいいと思う。
YAMLとかJSONとかそういうものではないが nginx の設定などにインスパイアされた、 人にもそこそこ読みやすく機械的にも扱える設定フォーマットを目指していることもあって、 慣れればそれなりに書きやすい、と思う。
data "aws_ami" "ubuntu" { most_recent = true filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"] } filter { name = "virtualization-type" values = ["hvm"] } owners = ["099720109477"] # Canonical } resource "aws_instance" "web" { ami = "${data.aws_ami.ubuntu.id}" instance_type = "t2.micro" tags { Name = "HelloWorld" } }
上記の設定はEC2のインスタンスを立ち上げる設定の例でterraformのマニュアルのもの。
ami
や instance_type
など AWS 固有の設定があることがわかると思う。
特徴的なのは属性値の参照、 ${data.aws_ami.ubuntu.id}
の部分で、
data "aws_ami" "ubuntu"
でフィルターして得られたAMIのidを使うという意味になっている。
terraformは設定ファイルに他の設定によって決定する値を埋め込むのが得意なため、 ひとまとまりの構成を比較的簡単に記述することができる。
これは各設定が依存するということでもあるが、記述量が大幅に減らせ変更にも強くなる。
裏返すと、変更が困難な箇所を変更する際に多くの箇所で変更を強いられる場合もあるが、 terraformには実行計画を事前に出力する機能があるため、一応意図しない大幅な構成変更は避けることができるようになっている。
stateファイル
terraformのもう一つの特徴が状態管理で、terraform.tfstate
という名前のファイルで実行時に状態を保存するようになっている。
このためterraform以外で(例えばマネジメントコンソール)リモート状態を変更すると手元の状態とリモートの状態が一致しなくなり問題が起こる場合がある。
基本的にterraformは1箇所で実行し terraform.tfstate
はたまにバックアップを取っておくのがよさそうだが、
terraform.tfstate
にはパスワードなどのセンシティブな情報が含まれることがあるので、gitで管理するのは避けたい。
中身はただのテキストなので、なんとなく手で直すこともできるし、壊れた場合は、importを使ってリモートの状態を tfstate
に取り込む方法もある。
terraform import
はドキュメントに細かい使い方が乗っているが、あくまでのリモート状態を手元に同期するだけで、
*.tf
ファイルを作ることはできないので注意。ただし、適当に作って terraform import
した後に差分がないように設定を自分で書くことはできる。
roadworker
わざわざterraformを使っているのにRoute53の管理はterraformを使わないのかという話になるんですが、
前述の通り、terraformには構成ファイル *.tf
を生成する機能はない。
これは既存の設定を取り込む必要がある場合に非常に面倒で、DNSのレコードが大量に存在する現場では厳しい。というかまさにこれ。
roadworkerのいいところは、設定ファイルを自動生成する機能がある点で、これだけでも使う価値がある。
生成時にzoneごとにファイルを分けることもできる。まあ、ゾーン内にrrsetが多すぎるとどのみち長くはなるが。
欠点はRubyで書かれているため、Rubyを導入できるだけの現場じゃないと導入が難しいところ。まあ、ここはゴリ押した。
あと、Ruby 2.4対応が完了していないため、Ruby 2.3で動かすのをオススメ。テスト機能で大量に警告が出る。 Rubyユーザとしては最新版で動かないのが少しモニョるが、rbenvとbundlerを使うなら環境は固定できるので、普段使いする分には困らないだろう。
終わりに
まあ当然といえば当然なんですが、用途に合わせて適切なツールは導入した方がいいですね。
学習コストの問題はありますが、ansibleにオーケストレーションを頑張らせるのは却って大変な気はします。
まあ、aws系モジュールのタスクが、boto/boto3を使ってAWS APIをそのまま呼び出していそうなところがplaybookを書くだけで見えてくる時点でお察しな感じはします。
あと、changedとかの判定も今ひとつだし、何より事前に実行計画を見ることができないのは痛いです。terraform plan
相当のことが、ansible-playbook -C
では達成できません。
もちろんプロビジョニングについては ansible は強力なツールです。うまく使い分けましょうというお話でした。(これを理解してもらうのがなかなか難しい
もうAWSのマネジメントコンソールからセットアップするの面倒なんでterraformでいいなという感想です
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月13日
現場からは以上です。
CentOS5にCentOS6の環境を作ってchrootする方法を書いておく
諸事情でCentOS5の環境を渡されたので、同じ不幸に見舞われた人向けに書いておく。
一般的な話でいえば、すぐにCentOS7の環境に移行すべきだが、世の中にはいろいろな不幸があるのでめげずに頑張ってほしい。
rinse でCentOS6をインストールする
CentOSでchroot環境を作るにはrinseというものがある。Debianでいうdebootstrapみたいなツールで、 rpmパッケージを展開し、chrootできるディレクトリツリーを構築する。
古くからあるパッケージなので、CentOS以外のディストリビューションでも利用できる。
rinse のセットアップ
Debianの場合以下のようにaptでインストールできる。
apt-get install rinse rpm
CentOS6のchroot環境を用意する
mkdir -p ./centos6 rinse --directory=./centos6 --distribution=centos-6 --arch=amd64
この状態で ./centos6
を持っていけばchroot環境を持ち出せる。簡単。
CentOS6にchrootする
sudo mount --rbind /dev ./centos6/dev sudo mount -t proc none ./centos6/proc sudo mount --rbind /sys ./centos6/sys sudo chroot ./centos6 /bin/bash
END
Pythonのパッケージ管理とsystemdでプロセスをずっと上げておく方法を書いておく
タイトルは半分当たっていて、半分は嘘。
Pythonをちゃんと環境作ってやったことが今までなかったので、今わかってる範囲の情報をまとめていく。
pip
Pythonのパッケージ管理システム。Pythonで作られたプロジェクトのインストールにもよく使われている。
依存パッケージの管理
pipにはfreeze
サブコマンドがあり、現在の環境で使っているパッケージとバージョンを出力できる。
このリストをrequirements.txt
で出力しておき、pipでこれをインストールするということがよく行われているらしい。
これらは後述するvirtualenv
やvenv
と組み合わせて使うとクリーンな環境を用意できる。
環境のパッケージを出力
pip freeze > requirements.txt
環境にパッケージをインストール
pip install -r requirements.txt
virtualenv
実行環境管理ツール。rvm
がツールとしては近い。
シェルと組み合わせて仮想環境を構築する。
仮想環境にpip
を使って必要なパッケージをインストールして、動作環境を作ることでpython環境を隔離できる。
と思ったけど、Python3.3からvenv
が公式に組み込まれたと聞きつけたので、virtualenvはもっぱらPython2系の環境を隔離したいときに使うことになる。
venv
Python3.3からバンドルされている環境管理ツール。 virtualenvと同様の機能を提供するが個別にインストールする必要はなく、Python3.3以降の環境であればデフォルトで使えると考えて良い。
python3 -m venv (環境名)
venvの実行例
python3 -m venv foo cd foo source bin/activate
venvが行うこと
他にもあるかもしれない。あんまりちゃんと読んではいない。
注意点
source
を使って追加のスクリプトをシェルに食わせているので、環境はディレクトリ以下でなくとも有効。- 解除するには
deactivate
を使うが、同じ名前の関数を用意しているとハマるので注意する- まあ大した問題ではない気もする
venv環境の切り方
この辺りから我流になってくるが、動作させたいプロジェクトのディレクトリを作ったらその名前でvenvを用意してもいいと思う。
共通で使えるvenvを用意するとすぐ書き始められる利点はあるが、依存パッケージの管理と言う面ではややとっ散らかりそうな雰囲気があるので慣れてくるまでは控える。
環境を揃える
インストール
brew install python3
PATHを通す
pipでインストールされるスクリプトを簡単に呼び出せるように PATH
に追加しておくと便利。
export PATH="$HOME/Library/Python/3.6/bin:$PATH"
PDB
Pythonのデバッグツール。とりあえず適当に試したいときに使えば便利っぽい。
インタラクティブコマンド
whatis
オブジェクトの型を調べるときに使う。
> whatis res[0] <class 'dict'>
venv環境でwebサーバのように永続的に動くものをsystemdで起動する
venv環境は環境変数を切り替えた上でシンボリックリンクやコピーを使って仮想環境を構築しているので
、仮想環境にpip
で依存ライブラリをインストールした後は、仮想環境内の /bin
以下に置かれた実行可能スクリプトを直接呼び出すだけで同様の動作にできる。
例えば以下のように systemd を使って起動できる。
[Unit] Description=Gunicorn instance to serve the falcon application After=network.target [Service] User=centos Group=centos PIDFile=/tmp/gunicorn.pid Environment="PATH=/home/centos/venv/project-name-env/bin" WorkingDirectory=/home/centos/project-name ExecStart=/home/centos/venv/project-name-env/bin/gunicorn index:app --bind=0.0.0.0:8000 --reload ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s TERM $MAINPID
この点はRubyのbundlerと比較して簡単に書けるので好き。結婚したい。
その他
コーディングスタイルガイド
終わり
こんなところか。あとは適当にコード書いていけばいい気はする。
とりあえずPythonはマニュアル読めばだいたい書けそうだし、 ライブラリもそれなりに充実しているので、Webアプリケーションを作るくらいなら苦労はしなさそうだ。
git-browse-remoteが恋しくなったのでgolangで書いてみた
現職場で何か足りないなーと思っていたことがあって、そうか git-browse-remote
かと思ったので、お得意の gem install
しようと思いましたが、
手元のRubyはバージョンアップのたびに入れなおすのが面倒と思ったので、golangの勉強がてらgoで書き直すことにしました。
urfave/cli
が割と簡単でこれくらいのコマンドなら簡単に作れるのがいいなと思いました。
あまり時間もかかっていませんが、golangに慣れたという感じもしないのが不思議ですね。
Visual Studio Codeを使って書いてみましたが、特にそれほど設定しなくても便利という感想です。
if
とか for
くらいしか使ってないので、スライスとかそういう概念がほぼなく練習にするにしてももうちょっと機能があるものにすればよかったかもと思いましたが、まあいいか...。
Pythonほどマニュアル見ただけで使えるようになってないけど、追々慣れていく...
勉強がてらでいうと docker とかもキメておきたいな、時間の有り余る今こそ修行
HOMEを手に入れる話
世の中にはいろいろな不幸がある。今回の不幸はユーザが作れないLinuxサーバの運用を任されたことだ。
まあ、こんな不幸は滅多に遭遇することでもないとは思うけど、今後また同じ不幸に遭遇した時のために書いておく。
こんな情報いるのか?という疑問もあるけど、不幸にもぶち当たった人のヒントになるかもしれない。ホント、みんな useradd
に感謝したほうがいい。
ホームディレクトリ
useradd
ができない環境では自分のユーザを作成できず、共通のユーザで操作することになるため、.toprc
のようないわゆるドットファイルを用意することができない。
今まで触ってきた環境があまりにもぬるま湯過ぎたのか、この事態に対処する方法がすぐには思いつかず、構築されたサーバと運用ルールを呪ったものだが、幸い他の作業をする時間があったため Linuxのホームディレクトリについて調べることにした。
まあ、いわゆるホームディレクトリについて書かれている。マルチユーザで使う時にユーザが自由にファイルを作成できるディレクトリというなんともオアシスのような世界について記述されている。
しかし現実の世界に自由はない。そもそもマルチユーザなんて世界じゃないし。
そうそう、ホームディレクトリはログインした時のワーキングディレクトリで /etc/passwd
に記述されている。
そしてホームディレクトリは環境変数 $HOME
に格納され、多くのプログラムがこれを参照する仕組みになっている。
$HOME
を設定するのはログインシェルで具体的には sshd
から呼び出される bash
みたいなものになるが、sshで接続した直後に環境変数$HOME
を設定できれば実質的なホームディレクトリが手に入る。
sshdのAcceptEnv
sshd
の設定にローカルから送られた環境変数を引き継ぐ AcceptEnv
という設定がある。
ただ、この設定は sshd
の設定で、反映には sshd
を再起動する必要があるし、
クライアント側でも SendEnv
を書く必要があるとはいえ、AcceptEnv HOME
ってのはかなりヤバい気がする。
sshでシェル起動時に環境変数を渡す
まあこっちのほうが現実的か。ログインシェルを変更する用途にも使えて便利だし。
こっちの方法は、 ssh
で bash
のようなシェルをログインモードで起動するようコマンドを渡し、その際に環境変数を上書きするという方法。
ssh -t remote_addr HOME=/tmp /usr/bin/bash -i -l
ssh
のオプション -t
は tty の割り当て。コマンドを渡す場合にはデフォルトでは tty
が生成されないため。
bash
のオプション -l
はログインシェル、-i
はインタラクティブモード。これらを指定するとよく見る入力待ちの端末が出来上がる。
ただ、ログイン直後のカレントディレクトリは /tmp
になっていない。
ログイン後 cd
するのもいいが、/tmp/.bashrc
の最後に cd
と書いておけばいいだけではある。
あと、ssh-keygen
のように一部のプログラムは $HOME
を参照しない。まあ、こいつらは数が少ないので大抵は無視できる。
終わりに
長々と書いたけど、こういう不幸にはあまり遭遇したくない。
シェル周りのオプションを調べたり、sshのことをこんなに調べるなんてことは今までなかったから面白くはあったけど普通こんなことしないし。
単に top
打ったときの動作をいい感じにしたりするのにこんなことしないといけない環境を若い子には触らせたくないね。
あ、そうそう。実はもう一つの不幸に遭遇していて、そっちは timestamp_timeout=0
を設定された環境を任されたことだけど、これは解消したからよしとする(よくはない)。