コードを書く日々:フリーランスエンジニアの技術メモ

何度も同じことをググってしまう自分の備忘録です。何か調査した際には、そのエッセンスを記事としてまとめ、とりあえず共有することを心がけています。

ghコマンドで複数のgithubアカウントを制御する

個人開発・業務・OSS活動などで複数のGitHubアカウントを使い分けたい。

マルチアカウント認証の構築

まずは、gh auth loginで各GitHubアカウントを認証する。アカウントごとにこのコマンドを実行し、CLI内部に複数の認証情報を登録。OAuth認証を利用するため、セキュリティも高い。一度認証すれば、毎回ログインし直す必要はない。

アクティブアカウントの切り替え

用途やプロジェクトごとにアカウントを切り替える場合、gh auth switchが役立つ。このコマンドでアクティブなアカウントを即座に変更できるため、コミットやプルリクエスト時の誤用を防げる。現在のアクティブアカウントはgh auth statusで確認可能。

アカウント情報の整理と削除

不要になったアカウントの認証情報は、gh auth logoutで削除できる。定期的なクリーンアップでセキュリティリスクを下げ、管理もシンプルに保てる。複数アカウントを扱うなら、不要な認証情報を残さない運用が重要。

プロジェクト単位でのアカウント分離

プロジェクトごとにアカウント設定を自動で切り替えたい場合、GH_CONFIG_DIR環境変数を活用する。さらにdirenvと組み合わせれば、ディレクトリごとの設定切り替えも自動化できる。プロジェクト移動と同時にアカウント設定も切り替わる快適な運用が実現する。

SSHキー・git設定との連携

CLI認証だけでなく、git操作時のユーザー設定やSSHキー管理も重要。各アカウントごとにSSHキーを用意し、~/.ssh/configでホストごとに切り替えることで、push/pull時のアカウント混同を防げる。.gitconfigincludeIfを使えば、ディレクトリ単位でユーザー情報を自動的に切り替えられる。

効率的なアカウント運用のために

ghコマンド2.40.0以降ではマルチアカウント対応が強化されている。gh auth logingh auth switchgh auth statusを組み合わせて、アカウント管理のワークフローを効率化できる。環境変数やdirenv、SSH、gitの設定と連携することで、現場のニーズに合わせた柔軟なアカウント運用が可能。

まとめ

複数アカウント運用の煩雑さは、ghコマンドの活用で大幅に軽減できる。認証、切り替え、クリーンアップ、自動化を組み合わせ、プロフェッショナルなGitHubアカウント管理を実現しよう。

よいGitHubライフを。

Dockerコンテナの再起動ポリシー「always」を一括で「no」に変更する

Dockerを運用していると、コンテナの再起動ポリシーを「always」に設定しているケースが多々あります。しかし、運用方針の変更などで「always」から「no」へ一括で切り替えたい場合、手動で1つずつ設定を変更するのは手間がかかります。
この記事では、該当するコンテナを一括で「no」に変更する方法を解説します。

1. 「always」ポリシーのコンテナIDを取得する

まず、再起動ポリシーが「always」になっているコンテナのIDを抽出します。
以下のコマンドを実行してください。

docker inspect -f '{{.Id}} {{.HostConfig.RestartPolicy.Name}}' $(docker ps -aq) | grep ' always' | awk '{print $1}'

このコマンドは、すべてのコンテナに対して再起動ポリシーを調べ、「always」となっているコンテナのIDだけをリストアップします。

2. すべての「always」コンテナの再起動ポリシーを「no」に変更する

取得したコンテナIDに対して、再起動ポリシーを「no」に変更します。
以下のワンライナーを実行してください。

docker inspect -f '{{.Id}} {{.HostConfig.RestartPolicy.Name}}' $(docker ps -aq) | grep ' always' | awk '{print $1}' | xargs -r docker update --restart=no

このコマンドは、先ほど抽出したIDをもとに、該当するすべてのコンテナの再起動ポリシーを「no」に一括変更します。

補足

  • docker update --restart=no は、実行中のコンテナにも即座に適用されます。
  • --rm オプション付きで起動したコンテナには適用できません。
  • 必要に応じて sudo を付けて実行してください。

まとめ

Dockerコンテナの再起動ポリシー「always」を一括で「no」に変更するには、
上記のワンライナーを実行するだけで簡単に対応できます。
これにより、Dockerの再起動時やコンテナ終了時に自動で再起動しなくなります。
運用方針の変更や一時的な設定変更時などに、ぜひ活用してみてください。

Dockerコンテナで再起動後に自動起動設定されているものを調べる

Dockerコンテナで再起動後に自動起動設定されているものを調べる方法

DockerコンテナがホストやDockerデーモンの再起動後に自動起動するかどうかは、「再起動ポリシー(restart policy)」の設定で決まります。
この設定が有効になっているコンテナを確認するには、以下の方法が使えます。


自動起動設定の確認コマンド

docker inspect -f "{{.Name}} {{.HostConfig.RestartPolicy.Name}}" $(docker ps -aq) | grep always
  • このコマンドは、すべてのコンテナ(起動中・停止中を含む)の名前と再起動ポリシーを一覧表示し、その中から「always」(常に自動起動)に設定されているものだけを抽出します。
  • 「unless-stopped」や「on-failure」など他のポリシーで絞り込みたい場合は、grep unless-stopped などに変更できます。

再起動ポリシーの種類

ポリシー名 説明
no 自動的に再起動しない(デフォルト)
always 常に再起動。ホストやDocker再起動時も自動起動
unless-stopped 明示的に停止しない限り再起動。ホストやDocker再起動時も自動起動
on-failure 異常終了(エラー時)のみ再起動(回数指定も可)

補足

  • 再起動ポリシーはdocker run時の--restartオプションや、docker update --restart=always コンテナ名などで設定できます。
  • docker-composeを使っている場合は、docker-compose.ymlの各サービスにrestart: alwaysなどを記述します。

まとめ

  • 上記のコマンドで「再起動後に自動起動するコンテナ」を一覧で確認できます。
  • ポリシーの違いを理解し、必要に応じて設定や変更を行ってください。

Laravel の response()->stream() について

基本概念

Laravel の response()->stream() はクライアントにストリーミングデータを送信するためのヘルパーメソッド。大容量のデータや継続的なデータ送信に最適な実装方法。

実装方法

基本的な使用例

Route::get('/stream', function() {
    return response()->stream(function() {
        foreach([1,2,3] as $item) {
            echo $item;
            ob_flush();
            flush();
            sleep(1);
        }
    });
});

内部実装の仕組み Laravel は内部的に Symfony\Component\HttpFoundation\StreamedResponse を生成して処理を実行。

public function streamDownload($callback, $name = null, array $headers = [], $disposition = 'attachment')
{
    $response = new StreamedResponse($callback, 200, $headers);
    
    if (!is_null($name)) {
        $response->headers->set('Content-Disposition', 
            $response->headers->makeDisposition(
                $disposition,
                $name,
                $this->fallbackName($name)
            )
        );
    }
    return $response;
}

実践的な使用例

リアルタイムメッセージ配信

public function __invoke()
{
    return response()->stream(function() {
        while (true) {
            if (connection_aborted()) {
                break;
            }
            
            $messages = Message::where('created_at', '>=', 
                Carbon::now()->subSeconds(5))->get();
                
            if ($messages) {
                echo "event: ping\n";
                echo "data: {$messages}\n\n";
            }
            
            ob_flush();
            flush();
            sleep(5);
        }
    }, 200, [
        'Cache-Control' => 'no-cache',
        'Content-Type' => 'text/event-stream'
    ]);
}

メモリ効率の最適化

大容量データ処理 メモリ使用量を抑えるため、cursor() メソッドを使用して1行ずつデータを処理。

public function download()
{
    $callback = function() {
        $stream = fopen('php://output', 'w');
        
        // ヘッダー処理
        fputcsv($stream, ['ID']);
        
        // データストリーミング
        $query = Model::orderBy('id');
        foreach ($query->cursor() as $record) {
            fputcsv($stream, [$record->id]);
        }
        
        fclose($stream);
    };
    
    return response()->streamDownload($callback, 'data.csv');
}

注意点

  • メモリ管理が重要
  • バッファリングの適切な制御が必要
  • コネクション切断の適切な処理が必要

PlaywrightをGitHub Actionsで実行

hello world的な内容ですが、何故か毎回ググってるのでメモ。

環境構成

使用バージョン

  • Playwright: v1.49.0

  • TypeScript: v5.6.3

  • Node.js: v23.2.0

GitHub Actions設定

GitHub Actionsの設定ファイル(.github/workflows/main.yml)は以下の構成。

name: Playwright Tests
on:
  push:
    branches: [ main, master ]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright Browsers
        run: npx playwright install --with-deps chromium

      - name: Run Playwright tests
        run: npx tsx test.ts
        env:
          PLAYWRIGHT_HEADLESS: true

設定の説明

トリガー設定 このワークフローはmainまたはmasterブランチへのプッシュ時に実行されます。

playwright.dev

実行環境 - Ubuntu最新版を使用 - タイムアウトは60分に設定 - Node.jsはLTS(Long Term Support)バージョンを使用

主要なステップ 1. リポジトリのチェックアウト 2. Node.jsのセットアップ 3. 依存関係のインストール 4. Playwrightブラウザ(Chromium)のインストール 5. テストの実行

playwright.dev

テストスクリプト

test.tsファイルは以下のような簡単なテストを実行します:

import { chromium } from '@playwright/test';

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto('https://google.com');
  await browser.close();
})();

特記事項

  • CIでの実行時はPLAYWRIGHT_HEADLESS環境変数trueに設定し、ヘッドレスモードで実行します
  • パフォーマンス最適化のため、Chromiumのみをインストールする設定としています

  • npm ciを使用することで、package-lock.jsonに基づいた厳密なインストールを実行します

github.com

npxとはそもそも何か。歴史など。

npxを当たり前のように使っているが、そもそもいつの間にあったんだっけ?と気になったのでまとめておく。

npxとは、Node Package Executor(ノードパッケージエグゼキューター)の略で、Node.jsのパッケージを一時的に実行するためのコマンドラインツールです。npmのバージョン5.2.0から導入され、現在では多くのNode.js開発者に利用されています。

npxの歴史と概要

npxは2017年7月にnpmバージョン5.2.0と共にリリースされました。それ以前は、開発者がパッケージを実行するためには、グローバルにインストールするか、package.jsonのscriptsセクションに定義する必要がありました。npxの導入により、これらの手順を簡略化し、より柔軟にパッケージを実行できるようになりました。

npxの主な機能と利点

  1. 一時的なパッケージのインストールと実行: npxを使用すると、ローカル環境にパッケージをインストールすることなく、一時的にパッケージをダウンロードして実行できます。これにより、環境を清潔に保ち、ディスクスペースを節約できます。

  2. バージョン指定実行: 特定のバージョンのパッケージを一時的にインストールして実行することができます。これは複数のバージョンを簡単に試したい場合に便利です。

  3. ローカルパッケージの簡単な実行: プロジェクトにローカルインストールされたパッケージを、フルパスを指定せずに簡単に実行できます。

  4. 環境の整理: 一度だけ使用するパッケージや頻繁に使用しないツールを実行する際に便利で、環境を整理しディスクスペースを節約できます。

npxの使い方

npxの基本的な使い方は以下の通りです:

npx <コマンド>

例えば、create-react-appを使用して新しいReactアプリケーションを作成する場合:

npx create-react-app my-app

このコマンドは、create-react-appパッケージを一時的にダウンロードし、my-appという名前の新しいReactプロジェクトを作成します。

特定のバージョンのパッケージを実行したい場合は、以下のように指定できます:

npx eslint@7.0.0 myfile.js

この例では、ESLintのバージョン7.0.0を使用してmyfile.jsを検証します。

npmとnpxの違い

npmはパッケージマネージャーであり、主にパッケージのインストール、アンインストール、更新を管理します。一方、npxはパッケージの実行に特化しています。

npmでパッケージをインストールする場合:

npm install <パッケージ名>

npxでパッケージを直接実行する場合:

npx <パッケージ名>

npxを使用すると、パッケージのインストールと実行を1つのコマンドで行え、使用後は自動的に削除されるため、環境を清潔に保つことができます。

npxの動作の仕組み

npxコマンドを実行すると、以下の順序でコマンドを探します:

  1. ローカルパッケージ(node_modules/.bin)
  2. 環境変数PATH
  3. npmレジストリ

特筆すべきは3番目のステップで、インストールされていないコマンドであっても、自動的にnpmレジストリからパッケージを探し、環境を汚さない場所にダウンロードして実行します。これにより、一時的な使用や異なるバージョンの試行が容易になります。

以上、npxの概要、歴史、主な機能、使い方について説明しました。npxは開発者の作業効率を向上させ、環境管理を簡素化する強力なツールとして、Node.js開発において重要な役割を果たしています。

vue-routerのワイルドカードキャッチ

vue-routerのワイルドカード(*)指定

vue3で使うVue Router 4で指定方法が変わってた。

import { createRouter, createWebHistory } from 'vue-router';
import HomePage from './components/HomePage.vue';
import NotFoundComponent from './components/NotFoundComponent.vue';

const routes = [
  { path: '/', component: HomePage },
  // ワイルドカードルート
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFoundComponent },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

正規表現(.)を使用してマッチさせて解決。

ん? なんで*じゃないの?

* と (.*) の違い

Vue Router 3(Vue 2用)までは、ワイルドカードルートを指定するために単純に*を使うことが一般的でした。これは、定義された他のルートにマッチしないすべてのパスに対してマッチするようなルートを設定する簡単な方法です。

しかし、Vue Router 4(Vue 3用)では、より複雑なパターンマッチングが可能になる正規表現を使用してルートパターンを定義することが推奨されています。ここで、/:pathMatch(.)の構文が使われるわけですが、この構文の各部分には以下のような意味があります。

/:pathMatchは、マッチしたパスの一部をキャプチャして、pathMatchという名前のパラメータに格納します。これにより、ルートのコンポーネント内で動的にマッチしたパスにアクセスできるようになります。 (.)は正規表現で、「任意の文字の0回以上の繰り返し」を意味します。つまり、どんなパスにもマッチすることを意味しています。 最後のは、このパターンが0回以上繰り返されることを許可します。これは、正規表現の一部というよりは、Vue Routerのパスマッチング機能におけるワイルドカードの繰り返しを示しています。

なぜ (.) なのか

この構文が採用されている主な理由は、Vue RouterがURLパスのセグメントをより柔軟にマッチさせ、キャプチャするための機能を提供することです。/:pathMatch(.)は「どんなパスにもマッチし、その全体をpathMatchパラメータとしてキャプチャする」という意味になります。

単に*を使用した場合、Vue Router 3までの挙動と同様に任意のパスにマッチするルートを定義できますが、Vue Router 4では正規表現を使ったより詳細なパターン定義が推奨されているため、この構文が標準的な方法として採用されています。