- 投稿日:
公式のドキュメントには書かれていない気がするがDockerだけあればセットアップ可能。WSL2でのセットアップが面倒なVargantは不要
本記事ではWSL2内のUbuntuの中でDockerとDocker Composeを使った構築法について記述する。Windows向けのDocker Desktopは使用しない
前提
- WSL2のUbuntuにVSCodeで接続して作業
- 起動してログイン、トゥート、設定と言った最低限の画面操作が可能な程度まで
確認環境
Env | ver |
---|---|
Mastodon | v3.5.3 |
Docker | 20.10.21, build baeda1f |
Docker Compose | v2.12.2 |
Ubuntu | 20.04.5 LTS |
WSL2 | 1.0.3.0 |
DevContainer | v0.266.1 |
VSCode | 1.73.0 |
手順
git clone https://github.com/mastodon/mastodon.git
- 最新版などバージョン指定が必要な場合は追加で
tag
をチェックアウトする
- 最新版などバージョン指定が必要な場合は追加で
- VSCodeでClone先を開く
- Reopen Containerする
- セットアップが走るので暫く待つ
foreman start
を流す- http://localhost:3000/ へアクセス
操作方法
ユーザーを作ったりしたい場合、Using the admin CLIが参考になる
一例としてユーザー作成は次の書式で行ける
./bin/tootctl accounts create foo --emaill foo@example.com --confirmed
トラブルシュート
DB接続エラーが出る
ActiveRecord::ConnectionNotEstablished at /
could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql//.s.PGSQL.5432"?
上記のエラーが出る場合、ビルドしたDockerイメージが壊れてるので以下のコマンドで全て消して作り直すとうまく行く
docker rm -f `docker ps -a -q`
docker rmi `docker images -q`
docker system prune
他のMastodonインスタンスが動かない
複数のMastodonインスタンスのDocker環境を同居させると多分コンフリクトする
- 投稿日:
Ubuntu22.04 LTSのターミナルのレンダリングが異常に重いのでバージョンを落として運用するためのメモ
Node.jsの開発環境だけ入れる
環境
環境 | Version |
---|---|
Windows 11 Pro | Build 22621.3155 |
Ubuntu | 20.04.6 LTS |
zsh | 5.8 (x86_64-ubuntu-linux-gnu) |
MariaDB | Ver 15.1 Distrib 10.3.38-MariaDB |
Docker | 20.10.17, build 100c701 |
Git | 2.42.0 |
WSL2の構成
- 管理者権限のPowerShellで以下を流す
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
- OS再起動
- Linuxカーネル更新プログラム パッケージをインストールする
- Ubuntuを入れる
Ubuntu側のセットアップ
適当な開発環境をサクッと
# systemdの有効化
cat <<EOF | sudo tee /etc/wsl.conf
[boot]
command=service docker start; service nginx start; service mysql start;
[interop]
appendWindowsPath = false
[user]
default=ここにユーザー名
EOF
sudo apt update -y
sudo apt upgrade -y
sudo apt install -y \
zsh \
ssh \
net-tools \
traceroute \
unzip \
mariadb-server \
nginx \
git \
keychain
# chsh
sudo apt -y install zsh unzip traceroute
chsh -s $(which zsh)
# Docker
sudo apt remove docker docker-engine docker.io containerd runc
sudo apt update
# 依存関係のインストール
sudo apt install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# Docker公式のGPG鍵を追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# リポジトリをパッケージマネージャーに登録
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
# docker本体のインストール
sudo apt install -y dockerdocker-ce docker-ce-cli containerd.io docker-compose-plugin
# sudo緩和
sudo usermod -aG docker $USER
# WSLをリブート
# dot file設定
git clone https://github.com/Lycolia/my-dotfiles.git
rm -Rf my-dotfiles/.git/
mv my-dotfiles/.* .
rm -Rf my-dotfiles/
# Node.js @ nvm
export NVM_DIR="$HOME/.nvm" && (
git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR"
cd "$NVM_DIR"
git checkout `git describe --abbrev=0 --tags --match "v[0-9]*" $(git rev-list --tags --max-count=1)`
) && \. "$NVM_DIR/nvm.sh"
nvm install --lts
# Keychain設定
cat <<'EOF' | tee -a ~/.zshrc
Keychain
keychain -q --nogui $HOME/.ssh/id_ed25519
source $HOME/.keychain/hostname-sh
EOF
トラブルシューティング
上記手順に書いてないことをすると起きるが、一応付記しておく
<3>WSL (639) ERROR: CreateProcessEntryCommon:345: getpwnam(USER_NAME) failed 0
というエラーが出る
wsl.conf
の[user]
セクションでdefault=USER_NAME
が存在しないユーザーを指定していると出る
Dockerやnginxのサービスが起動しない
systemdが有効になっていると起動しないので/etc/wsl.conf
からsystemd=true
を消す
- 投稿日:
ifの書き方メモ。中身はtest
コマンドなので[[]]
の中はtest
と同じ書き方が可能。コマンドなので演算子の間とかはスペースが無いとうまく動かない。余談だがzshでwhich
すると組み込みコマンドであることが確認できる
which [[
zsh: bad pattern: [[
which [
[: shell built-in command
which test
test: shell built-in command
基本構文
あくまでコマンドなので演算子の間には半角スペースが必要。[
より[[
の方が高機能らしい
https://fumiyas.github.io/2013/12/15/test.sh-advent-calendar.html
https://yukidarake.hateblo.jp/entry/2015/12/14/205610
if-elif-else
if [[ $var = "条件" ]]; then
# 処理
elif [[ $var -eq 0 ]]; then
# 処理
else
# 処理
fi
and / or
[[]]
を&&
か||
で区切れば成立する。これらは演算をしているわけではなく[[
の終了コードを見て次のコマンドを実行するかどうかを判断しているだけ
if [[ $var1 = "条件1" ]] && [[ $var2 = "条件2" ]]; then
# 処理
fi
if [[ $var1 = "条件1" ]] || [[ $var2 = "条件2" ]];
# 処理
fi
動作機序
test
コマンドは条件を満たせば0
、満たさなければ1
を終了コードに設定するため、単純にこれを利用している。[[
で代替可能なため基本的にtest
は使わない方がいい
# 条件1の$?が0なら条件2が走る
[[ $var1 = "条件1" ]] && [[ $var2 = "条件2" ]]
# 条件1の$?を無視して条件2が走る
[[ $var1 = "条件1" ]] || [[ test $var2 = "条件2" ]]
オプション
文字列用
オプション | 意味 | 補足 |
---|---|---|
string = string | 等しい | - |
string != string | 等しくない | - |
string =~ string | 正規表現一致 | - |
-n string | 空文字でない | non-zero |
-z string | 空文字 | zero |
-d path | ディレクトリ | directory |
-s path | ファイルサイズが 0 を超える | size |
数値用
オプション | 意味 | 補足 |
---|---|---|
0 -eq 0 | 等しい | equals |
0 -ne 0 | 等しくない | not equals |
0 -lt 0 | 未満 | less than |
0 -le 0 | 以下 | less than or equal to |
0 -gt 0 | 超える | greater than |
0 -ge 0 | 以上 | greater than or equal to |
ファイル用
オプション | 意味 | 補足 |
---|---|---|
-d path | ディレクトリ | directory |
-e path | 存在するパス | exists |
-f path | ファイル | file |
参考
- https://ss64.com/bash/test.html
- ifの書き方全般の説明がある
- 投稿日:
フルスクラッチで組むやつ
確認環境
Env | Ver |
---|---|
Ubuntu | 20.04.4 LTS |
nginx | 1.18.0 (Ubuntu) |
MariaDB | 15.1 Distrib 10.3.34-MariaDB |
grafana-server | Version 9.2.5 (commit: 042e4d216b, branch: HEAD) |
前提
- Windows側から
http://grafana.test/
としてアクセスする - DBにはMariaDBを使用
hostsの編集
Windows側のhosts
に以下を追記
127.0.0.1 grafana.test
各種環境のインストール
sudo apt update
sudo apt install -y nginx mariadb-server
sudo apt-get install -y apt-transport-https software-properties-common wget
sudo wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install grafana
nginxの設定
cat <<'EOF' | sudo tee /etc/nginx/conf.d/granafa.conf
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream grafana {
server localhost:4000;
}
server {
listen 80;
server_name grafana.test;
access_log /var/log/nginx/grafana.access.log;
error_log /var/log/nginx/grafana.error.log;
location / {
proxy_set_header Host $http_host;
proxy_pass http://grafana;
}
location /api/live/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_pass http://grafana;
}
}
EOF
sudo service nginx start
MariaDBの設定
ユーザー作成
id
とpw
の部分は適当に変える
sudo service mysql start
sudo mysql
CREATE USER 'id'@'%' IDENTIFIED BY 'pw';
GRANT ALL PRIVILEGES ON *.* TO 'id'@'%' WITH GRANT OPTION;
quit
外部接続テスト
適当なRDBクライアントから繋げればOK
grafanaの設定
sudo nano /etc/grafana/grafana.ini
で適当にいじる
# The http port to use
http_port = 4000
# The public facing domain name used to access grafana from a browser
domain = grafana.test
sudo service grafana-server start
- http://grafana.test/ へアクセス
- IDPW共に
admin
が初期
- IDPW共に
DBの読み込み
- MariaDBに適当なDBとテーブルを作る
- Grafanaにログインする
- サイドバーから
Configuration
-> Data sources - DBの情報を入れて接続
- 後はよしなにやる
- 投稿日:
割とハマってだるいので今回はサンプル程度にPRの一覧を取得して個別にSlackに投げるものを作ってみます
PRが2個ある場合、出力イメージはこんな感じ。2投稿に分けて投稿します
API トークンの入手
まずはSlack APIを叩くためのトークンをゲットします
- Create an appからアプリを作成
- 左のメニューからFeatures -> OAuth & Permissions
- Scopesを設定
- 今回はBot Token Scopesを
chat:write
とします
- 今回はBot Token Scopesを
- 左のメニューからSettings -> Install App to Your Teamでアプリをインストール
- トークンが吐き出されるのでメモする
GitHub Actions Workflowsの作成
SECRETの設定
- Slack APIトークンをリポジトリのSecretsに突っ込んでおきます
- 名前は一旦
SLACK_TOKEN
とします
Workflowsの作成
前提
- PR一覧の取得には actions/github-script を利用します
- GitHub内部の情報を抜いたり、JSで処理を組みたいときに重宝します
- APIリファレンスが読みやすいので、使うのにはあんま苦労しないと思います
- Slack APIを叩くのにはcurlを利用します
- actions/github-scriptから叩くのは多分難しいです
ベースの作成
これに肉付けをしていきます
name: Post to slack example
on:
workflow_dispatch:
jobs:
post-slack:
runs-on: ubuntu-latest
steps:
PR一覧の取得
List pull requestsにある通りに進めていきます
- uses: actions/github-script@v6
id: set-result
with:
result-encoding: string
script: |
const { data: respPulls } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
});
console.log(respPulls);
PR一覧の加工
こんなデータを取る感じで組んでいきます
API仕様は List pull requests を参照
type PullRequest = {
id: number;
reviewers: string[];
};
先ほど取得したrespPulls
を上記の型付けになるように加工します
const getReviewersName = (requested_reviewers) => {
return requested_reviewers.map((reviewers) => {
return reviewers.login;
});
};
const getPullRequests = (pulls) => {
return pulls.map((pull) => {
return {
id: pull.number,
reviewers: getReviewersName(pull.requested_reviewers),
};
});
};
const pulls = getPullRequests(respPulls);
Slackに投げるメッセージの作成
こんなメッセージをPRの数分組んでいきます
なお実際にSlackでメンションを作る場合はGitHubのスクリーン名とSlackのユーザー IDの突き合わせ処理が別途必要です。やり方は別途後述します
@foo @bar
https://example.com/pulls/1
やっていること
- 上記のフォーマットでメッセージを作成
- シェルスクリプトで配列として扱うためにBase64にエンコード
- 改行コードが混ざっていると扱いづらいので
- エンコードした文字列をスペース区切り文字列として連結
AAA BBB CCC ...
みたいな
- 最後にWorkflowsの戻り値として設定しています
const encodedMessages = pulls.reduce((messages, pull) => {
const reviewersBuff = pull.reviewers
.reduce((acc, cur) => {
return `${acc}${cur} `;
}, '')
.replace(/ $/, '');
const reviewers = reviewersBuff === '' ? 'レビュアー未設定' : reviewersBuff;
const message = `${reviewers}\\nhttps://example.com/pulls/${pull.id}`;
const encodedMessage = Buffer.from(message).toString('Base64');
return `${messages}${encodedMessage} `;
}, '');
return encodedMessages;
curlを利用してSlack APIを叩く
やっていること
encodedMessages=(${{steps.set-result.outputs.result}})
- 前項で作った文字列を配列として取得しています
for message in ${encodedMessages[@]}
- foreach的なやつです
- 改行コードがこの時点で存在すると上手くいきません
decoded_mes=$(echo ${message} | base64 -di)
- ここでBase64エンコードをデコードします
postSlack "$decoded_mes"
- 別引数にならないように
""
で固めます
- 別引数にならないように
- curl叩いてるところ
-d
の中をヒアドキュメントで展開するのが味噌です- 単純に文字列として扱うと変数展開が起きてJSONが壊れます
- run: |
postSlack() {
local mes=$1
curl -sS https://slack.com/api/chat.postMessage \
-H 'Authorization: Bearer ${{ secrets.SLACK_TOKEN }}' \
-H 'Content-Type: application/json; charset=UTF-8' \
-d @- <<EOF
{
token: "${{ secrets.SLACK_TOKEN }}",
channel: "#api-test",
text: "$mes"
}
EOF
}
encodedMessages=(${{steps.set-result.outputs.result}})
for message in ${encodedMessages[@]}
do
decoded_mes=$(echo ${message} | base64 -di)
postSlack "$decoded_mes"
done
コード全体
name: Post to slack example
on:
workflow_dispatch:
jobs:
post-slack:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6
id: set-result
with:
result-encoding: string
script: |
const getReviewersName = (requested_reviewers) => {
return requested_reviewers.map((reviewers) => {
return reviewers.login;
});
};
const getPullRequests = (pulls) => {
return pulls.map((pull) => {
return {
id: pull.number,
reviewers: getReviewersName(pull.requested_reviewers),
}
});
}
const { data: respPulls } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
});
const pulls = getPullRequests(respPulls);
const encodedMessages = pulls.reduce((messages, pull) => {
const reviewersBuff = pull.reviewers.reduce((acc, cur) => {
return `${acc}${cur} `
}, '').replace(/ $/, '');
const reviewers = reviewersBuff === '' ? 'レビュアー未設定' : reviewersBuff;
const message = `${reviewers}\\nhttps://example.com/pulls/${pull.id}`;
const encodedMessage = Buffer.from(message).toString('Base64');
return `${messages}${encodedMessage} `
}, '');
return encodedMessages;
- run: |
postSlack() {
local mes=$1
curl -sS https://slack.com/api/chat.postMessage \
-H 'Authorization: Bearer ${{ secrets.SLACK_TOKEN }}' \
-H 'Content-Type: application/json; charset=UTF-8' \
-d @- <<EOF
{
token: "${{ secrets.SLACK_TOKEN }}",
channel: "#api-test",
text: "$mes"
}
EOF
}
encodedMessages=(${{steps.set-result.outputs.result}})
for message in ${encodedMessages[@]}
do
decoded_mes=$(echo ${message} | base64 -di)
postSlack "$decoded_mes"
done
Appendix:Slackにメンションを投げる方法
Slackへ実際にメンションを投げるのはユーザーIDを指定する必要があります
参考:Formatting text for app surfaces
"text": "<@U024BE7LH> Hello"
のようにすることでメンションを投げられます
ユーザーIDはSlackアプリから相手のプロフィールを開き、そこにあるハンバーガーメニューみたいなやつから取れます。一応取得用のAPIもあります