環境構築を支える技術

自分はEC2で使い捨ての真っ新なUbuntuを立てては破棄してを繰り返して遊ぶことが多い
Neovim,zsh,tmuxあたりはdotfiles化しているが、各種言語/ツールのインストールは毎回コマンドを叩いたり、プロジェクト作成/Formatter&Linterのデファクトな方法などを毎回調べたりで面倒臭いのでまとめる
例えば最近だと、LLMで遊びたいけどPythonのプロジェクトってどうやって作るのが主流だっけ?Poetryだったはずだが?(最近また新しいのが出たとか聞いた)とか、普段使いじゃない言語だと特に

まずは、AWS EC2を立てる
毎回マネコンをポチってて良い加減面倒なので、
TerraformでVPCなどを含めて作成できるようにしておきたいので、そこからやる

GHAでOIDCでterraform applyしたいので、まずはその準備
以下はCloudShellで行う(こんな手軽なものがあったのか)
IAM identity providersの作成
aws iam create-open-id-connect-provider \
--url https://token.actions.githubusercontent.com \
--client-id-list sts.amazonaws.com
IAM roleの作成
適宜<>
を置き換え
cat <<EOF > trust-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:<OWNER>/<REPOSITORY>:*"
},
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF
aws iam create-role \
--role-name GitHubActionTerraformRole \
--assume-role-policy-document file://trust-policy.json
// 本来はもっと限定すべき
aws iam attach-role-policy \
--role-name GitHubActionTerraformRole \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
aws iam attach-role-policy \
--role-name GitHubActionTerraformRole \
--policy-arn arn:aws:iam::aws:policy/AmazonVPCFullAccess
aws iam attach-role-policy \
--role-name GitHubActionTerraformRole \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
state保存用のS3 bucketの作成
aws s3api create-bucket \
--bucket <BUCKET_NAME> \
--region ap-northeast-1 \
--create-bucket-configuration LocationConstraint=ap-northeast-1

リポジトリは
https://github.com/<OWNER>/<REPO>/settings/secrets/actions
で、ROLE_TO_ASSUME
、BACKEND_BUCKET
、MY_IPS
を設定しておく
この段階のcommit

まず、key pairを作成しておく
これもCloudShellで行う
aws ec2 create-key-pair \
--key-name <KEY_NAME> \
--query 'KeyMaterial' \
--output text
標準出力に秘密鍵が吐かれるので、コピってローカルに保存しておく
chmod 400 <sandbox.pem>

Ubuntu 24.04の最新のAMIのIDを知るコマンド
これもCloudShellで叩く
aws ec2 describe-images \
--region ap-northeast-1 \
--owners "099720109477" \
--filters "Name=name,Values=ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*" \
--query "sort_by(Images, &CreationDate)[-1].ImageId" \
--output text
(追記)
tfファイル内でもできそうなのでそちらに書いておく

EC2を立ち上げたコミット
SSHで入る
ssh -i <sandbox.pem> ubuntu@<PUBLIC_IP>

EC2立ち上げるだけで結構費やしてしまった
仕事ならもっとセキュアにやった方が良い箇所もあるが一旦これで

現在のdotfilesはinit.lua
1ファイルにまとめている(途中)
bash -c "$(wget -O- https://raw.githubusercontent.com/gtnao/dotfiles/main/install.sh)"
を叩けば前者の環境が結構ちゃんと構築されるようになっているが、
一旦色々見直したいので使わずに検討する

さて、SSHログインしたEC2内で色々入れていく
まずは
sudo apt update
sudo apt -y upgrade
絶対に必須そうなものを入れる
wget/curl/gitとかは入っているかもだが念為
unzipは入ってなくてコケることが多いので重要
sudo apt -y install \
wget curl git \
unzip \
build-essential

まず、入れたいものを洗い出す(適宜更新)
言語
メイン
- C/C++
- build-essentialを入れたので既にコンパイルできる
- Rust
- Golang
- Java
- Node
- Ruby
- Python
サブ
ツール
DevOps系
- docker
- k8s
- terraform
- クラウド(AWS/GoogleCloud)のCLI
Local系
- Neovim
- zsh
- tmux
- ripgrep
- ghq

コードを書くにはNeovim環境を整えないとどうしようもないので、そこから
Neovimは最新バージョンを入れたいので、GitHubから落としてくる
NEOVIM_VERSION=0.10.3
curl -LO "https://github.com/neovim/neovim/releases/download/v${NEOVIM_VERSION}/nvim.appimage"
chmod u+x nvim.appimage
./nvim.appimage --appimage-extract
sudo mkdir -p /opt/neovim
sudo mv squashfs-root /opt/neovim/
sudo ln -s /opt/neovim/squashfs-root/usr/bin/nvim /usr/local/bin/nvim
rm nvim.appimage
Ref

init.luaを配置する
これは当時のコミットハッシュのもの
mkdir -p ~/.config/nvim
curl -Lo ~/.config/nvim/init.lua https://raw.githubusercontent.com/gtnao/init.lua/6e8a30cbeac69146e7a4e04331303604a49553e2/init.lua
nvim
nodeがないとcopilotが動かないがそれ以外は動く

ghqを入れてgitリポジトリ管理をしたい
ghqを入れるためにGolangを入れる
Golang
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.23.4.linux-amd64.tar.gz
rm go1.23.4.linux-amd64.tar.gz
/usr/local/go/bin
以下にgoがあるのでパスを通す
~/go/bin
も
echo 'export PATH="/usr/local/go/bin:${PATH}"' >> ~/.bashrc
echo 'export PATH="${HOME}/go/bin:${PATH}"' >> ~/.bashrc
bash以外に変えるつもりだが一旦全部パスはbashrcに書いて通すこととする
ghq
go install github.com/x-motemen/ghq@latest
Ref
-
https://go.dev/dl/
- Linux x86-64のリンクをコピー
- https://github.com/x-motemen/ghq

と、その前に、ssh鍵を作ってGitHubに登録しないと怒られる
ghq get git@github.com:gtnao/init.lua.git
ln -sf "${HOME}/ghq/github.com/gtnao/init.lua/init.lua" ~/.config/nvim/init.lua
SSH
ssh-keygen -t rsa -b 2048 -f "${HOME}/.ssh/id_rsa" -N ""
chmod 600 "${HOME}/.ssh/id_rsa"
chmod 644 "${HOME}/.ssh/id_rsa.pub"
cat "${HOME}/.ssh/id_rsa.pub"
GitHubに登録しておく

各種言語の開発に必要なものを入れていく
C,C++
- build-essentialが入っているので最低限コンパイルできる
- CMakeを入れる
- Bazelも入れておく
sudo apt -y install cmake
sudo apt install apt-transport-https curl gnupg -y
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor >bazel-archive-keyring.gpg
sudo mv bazel-archive-keyring.gpg /usr/share/keyrings
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
sudo apt update && sudo apt -y install bazel
Ref
方針メモ
- CMakeは枯れているのでaptでOK
- Bazelはよう分からんが、よう分からんものはとりあえずaptで
- asdfを使うのは言語の処理系とかプロジェクトごとにバージョンをちょこちょこ変える必要があるものとする
- 自前でビルドしたりバイナリ取ってきたりするのは最新バージョンにこだわりがあるものとする
- eg. Neovim

以下、ホームディレクトリにsandboxディレクトリを切ってその中のサブディレクトリで試す
mkdir sandbox
cd sandbox
mkdir <hoge_sandbox>
随時必要なLSPやTreesitterはinit.luaに書き足していく
CMakeことはじめ
cmake_minimum_required(VERSION 3.28)
project(CmakeSandbox)
add_executable(main main.cpp)
mkdir build
cd build
cmake ..
make
./main
Bazelことはじめ
workspace(name = "my_project")
cc_binary(
name = "main",
srcs = ["main.cpp"],
)
bazel build //:main
./bazel-bin/main
Treesitterはstarlark

asdfを入れる
git clone https://github.com/asdf-vm/asdf.git "${HOME}/.asdf" --branch "master"
echo '. "${HOME}/.asdf/asdf.sh"' >> ~/.bashrc

asdfで各種言語を入れる
Node
asdf
LTS
sudo apt -y install python3 g++ make python3-pip
asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
asdf install nodejs 22.12.0
asdf global nodejs 22.12.0

Python
asdf
version
sudo apt -y install build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl git \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
asdf plugin-add python https://github.com/asdf-community/asdf-python.git
asdf install python 3.13.1
asdf global python 3.13.1

Ruby
asdf
version
sudo apt -y install autoconf patch build-essential rustc libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libgmp-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev libdb-dev uuid-dev
asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git
asdf install ruby 3.4.1
asdf global ruby 3.4.1

JVM系
SDKMAN!
SDKMAN!が主流らしい
zipが必要なので先に入れる
sudo apt -y install zip
curl -s "https://get.sdkman.io" | bash
echo 'source "${HOME}/.sdkman/bin/sdkman-init.sh"' >> ~/.bashrc
Java
LTS
sdk install java 21.0.5-tem
Gradle
sdk install gradle 8.12

Rust
Rustは一発
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
のはずだったが、
warning: it looks like you have an existing installation of Rust at:
warning: /usr/bin
warning: It is recommended that rustup be the primary Rust installation.
warning: Otherwise you may have confusion unless you are careful with your PATH
warning: If you are sure that you want both rustup and your already installed Rust
warning: then please replyy' or
yes' or set RUSTUP_INIT_SKIP_PATH_CHECK to yes
warning: or pass `-y' to ignore all ignorable checks.
error: cannot install while Rust is installed
warning: continuing (because the -y flag is set and the error is ignorable)
と出てしまう
rustc
だけ既に入っている
sudo apt -y remove rustc
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \
--default-toolchain stable \
--no-modify-path
-y
echo '. "${HOME}/.cargo/env"' >> ~/.bashrc

Docker
# Add Docker's official GPG key:
sudo apt update
sudo apt -y install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo無しで実行できるようにdocker groupに入れる
sudo usermod -aG docker $USER
newgrp docker

aquaを入れてk8s系のツールを試せるようにしておく
Golangが既に入っているのでgo getで
go install github.com/aquaproj/aqua/v2/cmd/aqua@latest
echo 'export PATH="$(aqua root-dir)/bin:$PATH"' >> ~/.bashrc

Terraform
terraformはasdfで入れる
asdf
asdf plugin-add terraform https://github.com/asdf-community/asdf-hashicorp.git
asdf install terraform 1.10.3
asdf global terraform 1.10.3
AWS CLI
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
gcloud
sudo apt update
sudo apt -y install apt-transport-https ca-certificates gnupg curl
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
sudo apt update && sudo apt -y install google-cloud-cli

Python周り
pipx
sudo apt -y install pipx
echo 'export PATH="~/.local/bin:$PATH"' >> ~/.bashrc
poetry
pipx install poetry
poetry config virtualenvs.in-project true

Poetry
poetry new <snake_case_project_name>
poetry add <module>
poetry install
portry run python <main.py>