エンジニアとして日々新しい知識をインプットしています。現在の職場には、毎日の終業時に日報を提出する文化があり、その中に「本日発見したこと・気づいたこと」を記載する欄が設けられています。私はこの欄を、業務で得た新しい知見や、業務外の自己学習で学んだことを記録するアウトププットの場として活用しています。この記事は、その日々の学びを知識として定着させ、いつでも振り返れる資産にするために、1ヶ月分をまとめたものです。
2025-10-1
terraform plan -generate-config-out=generated.tf -out=planfile
このコマンドの落とし穴を知ることができました。
・ -generate-config-out で出した generated.tf は、その planfile の構成スナップショットには含まれない
・そのため、生成後はもう一度 plan し直すか、planfile を使わずに apply する必要がある
実務での回避・運用パターン(どれか1つに寄せるとハマりにくい)
パターンA(おすすめ・シンプル)
1、terraform plan -generate-config-out=generated.tf(-out は付けない)
2、terraform apply(現在の構成=generated.tf を含む状態で実行)
パターンB(planfile を使いたい場合)
1、terraform plan -generate-config-out=generated.tf(ここでは planfile を作らない)
2、generated.tf を含めた構成で terraform plan -out=newplan
3、terraform apply newplan
パターンC(最初に最小のリソース定義を書いておく)
1、事前に最小限の resource “aws_cloudwatch_log_group” “access” { name = “…” } などを書く
2、plan -out planfile → apply planfile
3、その後に詳細属性を詰める(これなら最初の planfile に構成が含まれるため落ちない)
2025-10-2
.gitignore において、先頭に / が無いパターンはどの階層にもマッチすることを知りました。
.terraform/ では bootstrap/.terraform も無視される。つまり、.terraform/ は任意のサブディレクトリにある .terraform ディレクトリを全部無視する。逆にリポジトリ直下だけを対象にしたいなら / を付ける( /.terraform/ )
2025-10-6
git add -p (部分ステージング)について知ることができました。
・コミットに含める変更をハンク(hunk)単位、必要なら行単位で選び取るモード
・修正とリファクタが混在したとき、コミットを綺麗に分けられる
2025-10-7
シェルスクリプトにおける shift 2 と $1 / $2 の関係について知ることができました。
・シェルスクリプトに渡された引数は「位置パラメータ」として $1, $2, … に入る。残りの数は $#
・shift は左にずらす命令
・shift 1 なら $2 が $1 に繰り上がり、先頭1個を消費する
・shift 2 なら $3 が $1 に繰り上がり、先頭2個(フラグとその値)を消費する
・そのため、-b my-bucket のように「フラグ + 値」の2トークンを処理したら shift 2 で次の未処理の引数に進む
# 実行例:./script.sh -b my-bucket -p dev file1
echo “$1 | $2 | $3 | $4” # => -b | my-bucket | -p | dev
shift 2
echo “$1 | $2 | $3” # => -p | dev | file1
shift 2
echo “$1 | $2” # => file1 | (もう値は無い)
2025-10-8
sh/bash/zsh などで使える POSIX 標準の文字列テストである -z について知ることができました。
[[ -z “${bucket}” ]] && { echo “…”; exit 1; } [[ … ]] は Bash の条件式-z は文字列長が 0(空)なら真。ここでは bucket が空か判定
{ …; } はコマンドのグループ化(同一シェルで連続実行)。最後に ; を忘れずに
つまり、bucket が空ならエラーメッセージを出し、exit 1 で終了という流れ
※ set -u で未定義変数エラーオプションを設定している場合、最初に bucket=”” と初期化している限り、安全に -z 判定可能
2025-10-9
sh/bash/zsh などで使える POSIX 標準の文字列テストである -n について知ることができました。
[[ -n “${PROFILE}” ]] && export AWS_PROFILE=”${PROFILE}”・-n は文字列長が 1 以上(非空)なら真
・つまり上記の場合、PROFILE に値が入っていたら → AWS_PROFILE を export(子プロセスにも渡す環境変数に設定) [[ -n “${2-}” ]] || { echo “$1 には値が必要です”; exit 1; }
・ちなみに、|| は論理OR(左が失敗したら右を実行)
・想定済みの失敗を無視するなら、cmd || true
2025-10-10
外部キー制約として、下記のようにカスケード削除 / 更新の定義を省略した場合、MySQL/InnoDB では RESTRICT(親の削除/主キー更新は参照がある限りエラー)として扱われることを知りました。
CONSTRAINT `fk_settings_to_user`
FOREIGN KEY (`administrator_user_id`)
REFERENCES `careercloud_common`.`administrator_user` (`id`)
2025-10-14
AWS における Principal 指定などで利用可能な “arn:aws:iam::12345678:root” という「そのアカウント全体」を表す特別な書き方について知ることができました。
・その指定は「そのアカウント(12345678)に属するすべてのプリンシパル」を対象にする
・つまり、ルートユーザー/IAMユーザー/IAMロール/それらを引き受けたロールセッションが一致する
・アカウント全体を表す特別な書き方で、ルートユーザーだけに限定する意味ではない
・同等に “AWS”: “12345678” と書いても動作は同じ
・別アカウントのユーザーが 12345678 アカウント内のロールを引き受けた場合、結果のロールセッションは 12345678 のプリンシパルとして評価されるため、この指定に一致する(当然、そのロールの信頼ポリシーが許していることが前提)
2025-10-15
セキュリティグループの各ルールは環境側で個別に aws_security_group_rule を置き、SG本体はモジュール化するのが良いことを知りました。
環境差分に強い:本番/STGでポートや送信元が違うことが多い。モジュールに載せると過剰なパラメータ化か分岐が必要になり、可読性が落ちる
インポート容易性:既存ルールの取り込みは環境のリソースアドレスで行う方が単純。モジュール内に置くと module.path 付きの複雑なアドレスや for_each キー管理が増え、リファクタ時の整合が面倒
変更の爆発半径を限定:モジュール内にルールがあると、共通化のつもりで全環境に影響。環境側に置けば意図せぬ横展開を防ぎ、レビュートレーサビリティも高い
デプロイ分離/運用性:環境単位の変更・ロールバックがやりやすい。モジュールのバージョンアップ待ちが不要
Provider v5 の整合性:インラインルール混在を避け、すべて個別リソースに統一しやすい。重複ルールや衝突のデバッグが容易
権限/責務分離:VPC/SGのオーナーとアプリ側の責務を分けやすい。環境チームが自律的にルールを追加/削除できる。
Planの見通し:ルール差分が環境コードで完結し、変更意図が読みやすい。
例外(ルールをモジュール化するケース)
・ほぼ全環境で完全に同一のルールセットを使い回す場合のみ、専用「ルールセット・モジュール」を作るのは有効。ただし呼び出しは各環境から行い、共通化の範囲を明確に。
2025-10-16
下記事象に遭遇しました。結構苦戦しましたが、解決できて良かったです。
・DBクライアントからローカルの DBコンテナへ接続しようとすると Access denied が発生
・とはいえ、コンテナ内では mysql -u root -p でログイン(接続)可能
・DBクライアントから接続できないため、当然ホストから mysql -u root -p でも接続できない
原因
ホスト側で常駐していた MySQL が 3306 を既に待受しており、DBeaver がホストの MySQLに接続していたため。
その結果、Docker コンテナではなくローカル MySQL に対して認証が行われ、想定と異なるユーザ/パスワードや権限で拒否されていた。
詳細
lsof -iTCP:3306 -sTCP:LISTEN
mysqld … TCP localhost:3306 (LISTEN) ← ホストの MySQL が待受
com.docke … TCP *:3306 (LISTEN) ← Docker のポートフォワーダも待受
localhost は多くのクライアントで IPv4(127.0.0.1) に解決 → ホスト MySQL に到達しやすい
Docker 側も待受しているが、解決順の違いで DBeaver がホストに当たっていた
ホストに常駐していた MySQL を停止して 3306 を空ける対応を実施。解決
2025-10-22
Terraformのバックエンドに後からロックの機構を構築する方法を知ることができました。
(shared.tfbackend)
bucket = “hoge”
key = “shared/bootstrap.tfstate”
region = “ap-northeast-1”
encrypt = true
use_lockfile = true # 追加
ルートモジュールの作業ディレクトリで terraform init -reconfigure -backend-config=shared.tfbackend を実行
2025-10-24
Terraformにおいて、異なる OS/アーキテクチャの開発者がジョインする前に、メンテナが一度だけ以下を実行して複数プラットフォームのチェックサムを事前登録しておくと、他 OS で terraform init した際にロックファイルが毎回書き換わるのを防げることを知りました。
# 例:mac(ARM), Linux(amd64), Windows(amd64) を想定
terraform providers lock \
-platform=darwin_arm64 \
-platform=linux_amd64 \
-platform=windows_amd64
・これは依存ロックファイルにプラットフォーム別のプロバイダチェックサムを追記する公式コマンド
・ミラー配布などをしている場合にも有効
・ロックファイルは、init の副作用でも更新されるが、複数 OS をまとめて面倒見たい場合は terraform providers lock -platform=… を使うのが推奨
2025-10-24
あまり意識したことはなかったですが、EC2インスタンスとインスタンスプロファイルは 1:1 の関係、またインスタンスプロファイルとロールも1:1の関係であることを再認識しました。
・EC2インスタンスにアタッチできるインスタンスプロファイルは同時に1つだけ
・インスタンスプロファイル ⇔ ロールは 1:1(プロファイルは 1つのロールしか入れられない)
ただし、アプリ側で STS の AssumeRole を使えば、インスタンスロールから別アカウント/別ロールにスイッチすることができる(ロールA→ロールBの委任を許可しておく)
2025-10-28
Terraformにおいて、AMIなどはdataで参照することで、将来的に置換しやすいことを知りました。
・将来的に data 側の条件だけを差し替えて「最新の AMI を自動選択」などに切り替えられる。aws_instance 側の参照はそのままにできる
・例:名前パターン+most_recent、オーナー、タグ等での選択に変更するだけでローテーション可能
data “aws_ami” “selected” {
for_each = local.ec2_instances
most_recent = true
owners = [“self”] # 例: 自アカウント
filter {
name = “name”
values = [“myapp-${each.value.family}-*-x86_64-*”]
}
filter {
name = “virtualization-type”
values = [“hvm”]
}
}
# 参照側は変えない: data.aws_ami.selected[each.key].id
2025-10-29
Terraformにおいて、IGWはVPCモジュール内に含めて管理するのが適していることを知りました。
理由
1. リソースの密結合性
・IGWはVPCと1:1の関係で、VPCなしには存在できない
・IGWはvpc_idを必須パラメータとして持ち、VPCのライフサイクルに強く依存する
2. Terraformコミュニティのベストプラクティス
・AWS公式のterraform-aws-modules/vpcでも、IGWはVPCモジュール内で管理されている
・HashiCorpのドキュメントでも、VPCとIGWは同じモジュール内で定義されるパターンが一般的
3. 保守性・可読性
・VPCとIGWを同じファイル/モジュールで管理することで、ネットワークの基盤が一箇所で把握できる
・ルートテーブルでIGWを参照する際も、同じモジュールから出力される方が依存関係が明確
2025-10-30
NAT Gateway と EIP は 1:1 の密結合であるため、Terraform内では1つのモジュールで管理するのが自然であることを知りました。
2025-10-31
Terraform の組み込み関数である toset() について知ることができました。
・toset() は、リストをセット(集合)に変換する
・toset(list)
役割
・リスト(配列)をセット(集合型)に変換
・重複を自動的に削除
・要素の順序は保証されない
リストとセットの違い
重複: リスト → 許可 セット → 不可(自動削除)
順序: リスト → 保証される セット → 保証されない
インデックス:リスト → [0], [1], … セット → なし
for_each: リスト → 使えない セット → 使える