TECH PLAY

サイオステクノロジー(Tech.Lab)

サイオステクノロジー(Tech.Lab) の技術ブログ

524

PS-SLの佐々木です。 アドベントカレンダー13日目になります この記事では、Next.js 14プロジェクトにStorybookとPlaywright E2Eテストを導入し、Chromaticを使ってGitHub Actionsで自動ビジュアルテストを実現するまでの過程を解説します。 Chromaticとは Chromatic は、Storybookチームが提供するビジュアルテスト・UIレビュープラットフォームです。 なぜChromaticを使うのか 課題 Chromaticでの解決 CSSの変更が他のコンポーネントに影響していないか不安 全Storiesのスナップショットを自動比較 PRレビューでUIを確認するのが面倒 プレビューURLが自動でPRにコメントされる デザインシステムのドキュメントが古くなる 常に最新のStorybookがホスティングされる E2Eテストの画面キャプチャを管理したい Playwright連携でE2Eもビジュアルテスト化 今回のプロジェクト構成 project/ ├── frontend/ │ ├── src/ │ │ ├── components/ │ │ │ ├── ui/ # shadcn/ui ベースの共通コンポーネント │ │ │ │ ├── button.tsx │ │ │ │ ├── button.stories.tsx │ │ │ │ ├── card.tsx │ │ │ │ ├── card.stories.tsx │ │ │ │ ├── input.tsx │ │ │ │ ├── input.stories.tsx │ │ │ │ └── textarea.tsx │ │ │ ├── chat/ # チャット機能コンポーネント │ │ │ │ ├── MessageList.tsx │ │ │ │ ├── MessageList.stories.tsx │ │ │ │ ├── MessageInput.tsx │ │ │ │ └── ModeSelector.tsx │ │ │ └── import/ # インポート機能コンポーネント │ │ │ ├── FileUploader.tsx │ │ │ └── ImportProgress.tsx │ │ └── app/ │ ├── e2e/ # Playwright E2Eテスト │ │ └── home.spec.ts │ ├── .storybook/ │ │ ├── main.ts │ │ └── preview.ts │ └── package.json ├── backend/ └── .github/ └── workflows/ └── ci.yml 技術スタック Next.js 14 (App Router) shadcn/ui + Tailwind CSS Storybook 8.4 Playwright @chromatic-com/playwright Storybookのセットアップ 1. Storybookの初期化 cd frontend npx storybook@latest init 2. 設定ファイル .storybook/main.ts : import type { StorybookConfig } from '@storybook/nextjs' ; const config : StorybookConfig = { stories : [ '../src/**/*.mdx' , '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)' ] , addons : [ '@storybook/addon-essentials' , '@storybook/addon-interactions' , '@storybook/addon-links' , ] , framework : { name : '@storybook/nextjs' , options : { } , } , docs : { autodocs : 'tag' , } , staticDirs : [ '../public' ] , } ; export default config ; .storybook/preview.ts : import type { Preview } from '@storybook/react' ; import '../src/app/globals.css' ; // Tailwind CSSを読み込む const preview : Preview = { parameters : { controls : { matchers : { color : / (background|color)$ / i , date : / Date$ / i , } , } , } , } ; export default preview ; 3. package.jsonのスクリプト { "scripts" : { "storybook" : "storybook dev -p 6006" , "build-storybook" : "storybook build" , "chromatic" : "chromatic --exit-zero-on-changes" } } コンポーネントのStories作成 実際に作成したStoriesの例を紹介します。 UIコンポーネント(Button) src/components/ui/button.stories.tsx : import type { Meta , StoryObj } from '@storybook/react' ; import { Button } from './button' ; const meta : Meta < typeof Button > = { title : 'UI/Button' , component : Button , parameters : { layout : 'centered' , } , tags : [ 'autodocs' ] , argTypes : { variant : { control : 'select' , options : [ 'default' , 'destructive' , 'outline' , 'secondary' , 'ghost' , 'link' ] , } , size : { control : 'select' , options : [ 'default' , 'sm' , 'lg' , 'icon' ] , } , } , } ; export default meta ; type Story = StoryObj < typeof meta > ; export const Default : Story = { args : { children : 'Button' , variant : 'default' , } , } ; export const Secondary : Story = { args : { children : 'Secondary' , variant : 'secondary' , } , } ; export const Outline : Story = { args : { children : 'Outline' , variant : 'outline' , } , } ; export const Destructive : Story = { args : { children : 'Destructive' , variant : 'destructive' , } , } ; export const Small : Story = { args : { children : 'Small' , size : 'sm' , } , } ; export const Large : Story = { args : { children : 'Large' , size : 'lg' , } , } ; 機能コンポーネント(MessageList) チャット機能のメッセージ一覧コンポーネント。様々な状態をStoriesで表現します。 src/components/chat/MessageList.stories.tsx : import type { Meta , StoryObj } from '@storybook/react' ; import { MessageList } from './MessageList' ; import type { Message } from '@/types' ; const meta : Meta < typeof MessageList > = { title : 'Chat/MessageList' , component : MessageList , parameters : { layout : 'fullscreen' , } , tags : [ 'autodocs' ] , decorators : [ ( Story ) => ( < div className = "h-[500px] bg-gray-50" > < Story / > < / div > ) , ] , } ; export default meta ; type Story = StoryObj < typeof meta > ; // モックデータ const mockMessages : Message [ ] = [ { id : '1' , role : 'user' , content : '冷却システムの変更点を教えてください' , timestamp : new Date ( '2024-01-15T10:00:00' ) , } , { id : '2' , role : 'assistant' , content : '冷却システムには以下の変更点があります:\n\n1. 冷却ファンの形状を変更\n2. ヒートシンクの素材を変更' , sources : [ { id : 'src-1' , content : 'No.15: 冷却システム' , excel_row : 15 } , ] , timestamp : new Date ( '2024-01-15T10:00:05' ) , } , ] ; // 空の状態 export const Empty : Story = { args : { messages : [ ] , isLoading : false , onExport : ( ) => { } , } , } ; // メッセージがある状態 export const WithMessages : Story = { args : { messages : mockMessages , isLoading : false , onExport : ( ) => { } , } , } ; // ローディング状態 export const Loading : Story = { args : { messages : [ mockMessages [ 0 ] ] , isLoading : true , onExport : ( ) => { } , } , } ; // エクスポートボタン付き export const WithExportButton : Story = { args : { messages : [ ... mockMessages , { ... mockMessages [ 1 ] , id : '3' , exportReady : true , // エクスポート可能フラグ } , ] , isLoading : false , onExport : ( ) => alert ( 'Export clicked' ) , } , } ; インポート機能(ImportProgress) ファイルインポートの進捗表示コンポーネント。各状態をStoriesで網羅します。 src/components/import/ImportProgress.stories.tsx : import type { Meta , StoryObj } from '@storybook/react' ; import { ImportProgress } from './ImportProgress' ; const meta : Meta < typeof ImportProgress > = { title : 'Import/ImportProgress' , component : ImportProgress , parameters : { layout : 'centered' , } , tags : [ 'autodocs' ] , decorators : [ ( Story ) => ( < div className = "w-[400px]" > < Story / > < / div > ) , ] , } ; export default meta ; type Story = StoryObj < typeof meta > ; export const Idle : Story = { args : { status : 'idle' , result : null , } , } ; export const Uploading : Story = { args : { status : 'uploading' , result : null , } , } ; export const Success : Story = { args : { status : 'success' , result : { success : true , message : 'Excelファイルのインポートが完了しました' , documentCount : 25 , } , } , } ; export const Error : Story = { args : { status : 'error' , result : { success : false , message : 'ファイル形式が不正です。xlsx または xls ファイルをアップロードしてください。' , } , } , } ; Playwright E2EテストのChromatic対応 1. パッケージのインストール npm install --save-dev @chromatic-com/playwright 2. E2Eテストの修正 通常の @playwright/test の代わりに、 @chromatic-com/playwright からインポートします。 e2e/home.spec.ts : // Before: import { test, expect } from '@playwright/test'; // After: import { test , expect } from '@chromatic-com/playwright' ; test . describe ( 'Home Page' , ( ) => { test ( 'should display the header' , async ( { page } ) => { await page . goto ( '/' ) ; await expect ( page . locator ( 'h1' ) ) . toContainText ( 'Excel RAG' ) ; // テスト終了時に自動的にスナップショットが取得される } ) ; test ( 'should have navigation links' , async ( { page } ) => { await page . goto ( '/' ) ; await expect ( page . getByRole ( 'link' , { name : 'QA' } ) ) . toBeVisible ( ) ; await expect ( page . getByRole ( 'link' , { name : 'Import' } ) ) . toBeVisible ( ) ; } ) ; test ( 'should display mode selector' , async ( { page } ) => { await page . goto ( '/' ) ; await expect ( page . getByRole ( 'button' , { name : 'QA' } ) ) . toBeVisible ( ) ; await expect ( page . getByRole ( 'button' , { name : 'Export' } ) ) . toBeVisible ( ) ; } ) ; test ( 'should have message input' , async ( { page } ) => { await page . goto ( '/' ) ; await expect ( page . getByPlaceholder ( '質問を入力してください' ) ) . toBeVisible ( ) ; } ) ; } ) ; test . describe ( 'Import Page' , ( ) => { test ( 'should display file uploader' , async ( { page } ) => { await page . goto ( '/import' ) ; await expect ( page . locator ( 'h2' ) ) . toContainText ( 'Excel帳票インポート' ) ; } ) ; } ) ; 3. Playwright設定 playwright.config.ts は通常通りでOK: import { defineConfig , devices } from '@playwright/test' ; export default defineConfig ( { testDir : './e2e' , fullyParallel : true , forbidOnly : ! ! process . env . CI , retries : process . env . CI ? 2 : 0 , workers : process . env . CI ? 1 : undefined , reporter : 'html' , use : { baseURL : 'http://localhost:3000' , trace : 'on-first-retry' , } , projects : [ { name : 'chromium' , use : { ... devices [ 'Desktop Chrome' ] } , } , ] , webServer : { command : 'npm run dev' , url : 'http://localhost:3000' , reuseExistingServer : ! process . env . CI , } , } ) ; GitHub Actionsでの自動化 StorybookとE2Eで別々のChromaticプロジェクトを使用する設定です。 完全なワークフロー設定 .github/workflows/ci.yml : name : CI on : push : branches : [ master , develop ] pull_request : branches : [ master , develop ] concurrency : group : $ { { github.workflow } } - $ { { github.ref } } cancel-in-progress : true jobs : # =========================== # Chromatic - Storybook # =========================== chromatic-storybook : name : Chromatic - Storybook runs-on : ubuntu - latest defaults : run : working-directory : frontend steps : - uses : actions/checkout@v4 with : fetch-depth : 0 # 全履歴取得(差分比較に必要) - name : Setup Node.js uses : actions/setup - node@v4 with : node-version : '20' cache : 'npm' cache-dependency-path : frontend/package - lock.json - name : Install dependencies run : npm ci - name : Build Storybook run : npm run build - storybook - name : Publish Storybook to Chromatic id : chromatic uses : chromaui/action@latest with : projectToken : $ { { secrets.CHROMATIC_STORYBOOK_TOKEN } } workingDir : frontend storybookBuildDir : storybook - static exitZeroOnChanges : true autoAcceptChanges : master onlyChanged : true - name : Comment Storybook URL on PR if : github.event_name == 'pull_request' uses : actions/github - script@v7 with : script : | const storybookUrl = '${{ steps.chromatic.outputs.storybookUrl }}'; const buildUrl = '${{ steps.chromatic.outputs.buildUrl }}'; if (storybookUrl) { github.rest.issues.createComment( { issue_number : context.issue.number , owner : context.repo.owner , repo : context.repo.repo , body : ` ## Storybook Preview\n\n- [View Storybook](${storybookUrl})\n- [View Chromatic Build](${buildUrl})` } ); } # =========================== # Chromatic - E2E (Playwright) # =========================== chromatic-e2e : name : Chromatic - E2E runs-on : ubuntu - latest defaults : run : working-directory : frontend steps : - uses : actions/checkout@v4 with : fetch-depth : 0 - name : Setup Node.js uses : actions/setup - node@v4 with : node-version : '20' cache : 'npm' cache-dependency-path : frontend/package - lock.json - name : Install dependencies run : npm ci - name : Install Playwright browsers run : npx playwright install - - with - deps chromium - name : Run Playwright tests run : npx playwright test - name : Publish E2E to Chromatic id : chromatic - e2e uses : chromaui/action@latest with : projectToken : $ { { secrets.CHROMATIC_E2E_TOKEN } } workingDir : frontend playwright : true exitZeroOnChanges : true 必要なGitHub Secrets GitHubリポジトリの Settings > Secrets and variables > Actions で設定: Secret名 用途 取得方法 CHROMATIC_STORYBOOK_TOKEN Storybook用 Chromaticで「Storybook」プロジェクトを作成 CHROMATIC_E2E_TOKEN E2E用 Chromaticで「E2E」プロジェクトを作成 なぜ分けるのか? StorybookとE2Eは性質が異なるため、別プロジェクトで管理する方が見やすくなります: Storybook: コンポーネント単位のスナップショット E2E: ページ全体のスナップショット Chromaticの画面を見てみる 実際にPRを作成したりtargeブランチにPRがマージされると以下のように確認することができます。 Buildごとにどのコンポーネントがどのように変更されているかがスナップショットで確認できるようになっており、これを承認したりコメントを残したりすることができます。 UIはソースコードを眺めているだけではなかなか差分がわかりにくいため実際のビジュアルを手軽にできるのはとても良い機能だと思います。 ハマったポイントと解決策 1.   chromatic --playwright でアーカイブが見つからないエラー Chromatic archives directory cannot be found: /path/to/frontend/test-results/chromatic-archives 原因 : Playwrightテストを実行する前に chromatic --playwright を実行していた 解決策 : 先にPlaywrightテストを実行してからChromaticにアップロード - name : Run Playwright tests run : npx playwright test - name : Publish E2E to Chromatic uses : chromaui/action@latest with : playwright : true 2.   takeArchive が見つからないエラー Module '"@chromatic-com/playwright"' has no exported member 'takeArchive'. 原因 : 古いドキュメントを参照していた 解決策 :   @chromatic-com/playwright からは test と expect をインポートするだけでOK。テスト終了時に自動的にスナップショットが取得される。 // ❌ 間違い import { takeArchive } from '@chromatic-com/playwright' ; // ✅ 正しい import { test , expect } from '@chromatic-com/playwright' ; 3. Storybookビルドエラー(webpack関連) Module not found: TypeError: Cannot read properties of undefined (reading 'tap') 原因 :   @chromatic-com/playwright が古いStorybookバージョンを要求し、バージョン競合が発生 解決策 : Storybookのバージョンを8.4.2に統一 npm install @storybook/nextjs@8.4.2 @storybook/addon-essentials@8.4.2 \ @storybook/addon-interactions@8.4.2 @storybook/addon-links@8.4.2 \ @storybook/blocks@8.4.2 @storybook/react@8.4.2 @storybook/test@8.4.2 \ storybook@8.4.2 4. Chromaticの storybookBuildDir が必要 CIでStorybookをビルドしてからアップロードする場合、ビルド済みディレクトリを指定する必要がある。 - name : Build Storybook run : npm run build - storybook - name : Publish to Chromatic uses : chromaui/action@latest with : storybookBuildDir : storybook - static # これを指定 まとめ 導入後のワークフロー 開発者がPRを作成 GitHub ActionsがStorybookをビルド → Chromaticにアップロード GitHub ActionsがE2Eテスト実行 → Chromaticにアップロード PRにStorybookプレビューURLが自動コメント レビュアーがChromaticで差分を確認 問題なければマージ → masterブランチは自動承認 作成したファイル一覧 frontend/ ├── src/components/ │ ├── ui/ │ │ ├── button.stories.tsx │ │ ├── card.stories.tsx │ │ ├── input.stories.tsx │ │ └── textarea.stories.tsx │ ├── chat/ │ │ ├── MessageList.stories.tsx │ │ ├── MessageInput.stories.tsx │ │ └── ModeSelector.stories.tsx │ ├── import/ │ │ ├── FileUploader.stories.tsx │ │ └── ImportProgress.stories.tsx │ └── Introduction.mdx # デザインシステムドキュメント ├── e2e/ │ └── home.spec.ts # Chromatic対応済み ├── .storybook/ │ ├── main.ts │ └── preview.ts └── package.json .github/workflows/ └── ci.yml # Chromatic自動化設定 得られた効果 Before After UIレビューは手動で各画面を確認 PRにプレビューURLが自動投稿 CSS変更の影響範囲が不明 全コンポーネントのスナップショットで差分検出 E2Eテストは結果のみ確認 画面キャプチャも自動で比較・管理 デザインシステムのドキュメントが陳腐化 常に最新のStorybookがホスティング Chromaticを導入することで、UIの品質を担保しながら開発スピードを落とさないワークフローが実現できました。 参考リンク Chromatic公式ドキュメント chromaui/action (GitHub Action) @chromatic-com/playwright Storybook公式サイト ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Next.js + Storybook + PlaywrightをChromaticでビジュアルテスト自動化する first appeared on SIOS Tech Lab .
アバター
はじめに こんにちは、サイオステクノロジーの小野です。SIOS Tech Labアドベントカレンダー12日目の投稿です。 「SIOS社員が一年で学んだこと」がアドベントカレンダーのテーマですが、私はこの一年間〇〇Opsといった様々な開発・運用の効率を上げる仕組みを学んできました。 例えば、 OpenShift AIによってAIモデル開発の効率化を行うMLOps OpenShift AIのデータサイエンスパイプラインについて GitLabのCI/CDパイプラインとGateKeeperを組み合わせてセキュリティが高い状態で自動デプロイを行うDevSecOps DevSecOps実践ガイド:CI/CD環境の構築編 そして現在はRancher FleetのHelmOpsについて学んでいます。 今回はKubernetesクラスター環境へのアプリケーション自動デプロイ(CD)手段として、HelmOpsについて解説します。 ちなみにDevOpsから派生したこれらの〇〇Opsという名前が付く仕組みをまとめてxOpsと呼ぶそうです。 GitOps HelmOpsの説明をする前にアプリケーションの自動デプロイ手段として一般的なGitOpsについて解説します。 GitOpsとはGitリポジトリを唯一の信頼できる情報源(Single Source of Truth)として扱います。要するに、Gitリポジトリ内のソースコードの状態とデプロイされているアプリケーションの状態を自動的に同期する仕組みです。 したがって、Gitリポジトリの更新をするだけで、アプリケーションとそれがデプロイされているインフラ環境を自動的に更新することができます。 さらにGitでインフラ環境を管理できるので、インフラ環境のバージョン管理やロールバックがしやすいです。 例としてKubernetesクラスターにデプロイされているアプリケーションをGitOpsによって自動的に更新する流れについて解説します。 GitOpsフローの流れ(アプリケーションの更新の例) CIプロセス アプリ開発者がソースコードを更新し、アプリ用リポジトリにPushして、ブランチをマージする。 CIツールがアプリ用リポジトリの更新を検出すると、アプリケーションのコンテナイメージをビルドして、コンテナレジストリに保存する。 CIツールが新しいコンテナイメージを参照するようにHelmチャートをパッケージ化する。その後、このHelmチャートをHelmレジストリに保存する。 CDプロセス アプリ開発者が新しいHelmチャートを利用するようにアプリケーションのマニフェストファイルを更新し、設定用リポジトリにPushして、ブランチをマージする。 CDツールがGitリポジトリの更新を検出すると、設定用Gitリポジトリ内の設定ファイルを参照して、アプリケーションとそれがデプロイされているKubernetesクラスター環境を設定ファイルと同期させる Kubernetesクラスターが新しいHelmチャートと新しいコンテナイメージを利用してアプリケーションを更新する この説明ではCIとCDの区別をわかりやすくするために、あえてCDプロセスの設定用リポジトリの更新を開発者が行うようにしましたが、CIツールがコンテナイメージとHelmチャートの更新をした後、自動的に設定用リポジトリを更新することで、CIからCDまで自動化する場合もあります。 HelmOps HelmOpsとはHelmレジストリを唯一の信頼できる情報源(Single Source of Truth)として扱います。要するに、Helmレジストリ内のチャートファイルの状態とデプロイされているアプリケーションの状態を自動的に同期する仕組みです。 GitOpsとの差異はGitレジストリと同期するかHelmレジストリと同期するかの違いです。 HelmOpsも同様に、例としてKubernetesクラスターにデプロイされているアプリケーションをHelmOpsによって自動的に更新する流れについて解説します。 HelmOpsフローの流れ(アプリケーションの更新の例) CIプロセス アプリ開発者がソースコードを更新し、アプリ用リポジトリにPushして、ブランチをマージする。 CIツールがアプリ用リポジトリの更新を検出すると、アプリケーションのコンテナイメージをビルドして、コンテナレジストリに保存する。 CIツールが新しいコンテナイメージを参照するようにHelmチャートをパッケージ化する。その後、このHelmチャートをHelmレジストリに保存する。 CDプロセス HelmOpsツールがHelmレジストリの更新を検出すると、Helmレジストリ内のHelmチャートを参照してアプリケーションとそれがデプロイされているKubernetesクラスター環境を設定ファイルとHelmチャートと同期させる Kubernetesクラスターが新しいHelmチャートと新しいコンテナイメージを利用してアプリケーションを更新する HelmOpsはCDプロセスでGitを介さずにアプリケーションの更新を行うことができるので、シンプルな構成にできます。ただし、設定用Gitリポジトリを利用しない都合上、環境ごとにカスタマイズしてデプロイすることが難しくなります。 終わりに HelmOpsの仕組みについて解説しました。カスタマイズとその管理がしやすいGitOpsとシンプルな構成のHelmOpsについてはうまく使い分けることで、さらなる運用効率を上げることができるのではないかと思います。 参考 https://ndigi.tech/all_post/24547 https://about.gitlab.com/ja-jp/topics/gitops/ https://fleet.rancher.io/helm-ops https://www.docswell.com/s/yassan/5PGJG6-rancherjp-online-meetup-07#p1 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post GitOpsだけじゃない!新たな選択肢「HelmOps」とは? first appeared on SIOS Tech Lab .
アバター
サイオステクノロジー武井です。今回は自宅にデジタルサイネージを導入した話をします。仕事とはまったく関係ないです。 デジタルサイネージとは? デジタルサイネージとは、電子的な看板のことです。店舗や公共の場で情報を表示するために使用されます。テレビやモニターを使って、広告や案内、ニュースなどを表示します。 モチベーション 私が自宅に導入したデジタルサイネージはこんな感じです。 全景はこんな感じです。 普通の人は自宅にデジタルサイネージ導入しないと思いますが、私は多分普通じゃないので。。。   で、きっかけとしては、自宅のデスクを飛行機のコックピットみたいにかっこよくしてみたいと言う理由だけで導入したのですが、実際に入れてみるとこれが意外にすごい便利でした。 デジタルサイネージの画面 デジタルサイネージの画面の構成はこんな感じです。 左上に時計と祝日のカレンダー、右上に現在の天気と予報、真ん中に直近(12時間先まで)の雨予報、その下にニュースヘッドライン、その下にニュースのYouTubeのライブ動画を垂れ流しています。 これ、すごい便利なんですよね。まぁ、全部普通にスマホで見れるでしょって感じなんですけど、やっぱ、視線をぱっと動かしただけで、必要な情報が全部見れるってのはすごい便利です。雨予報とかニュースのYouTubeとか個別にスマホで見るのは面倒くさいですからね。 直近の雨予報表示しているのは実は自作している部分なのですが、これ、洗濯物をしまうかどうかの判断にとても役立っておりまして、、洗濯物を外に干しているときに、あと何時間後に雨が降るかがぱっとわかるので、洗濯物をしまうタイミングが非常にわかりやすいです。 構成 デジタルサイネージを実現するソフトウェアはオープンソースのMagicMirror2というものを使用しています。これは一言でいえば 「Web技術で作られた、超拡張可能なスマートミラー/デジタルサイネージ用フレームワーク(OSS)」 であるといえます。 https://magicmirror.builders/ MagicMirror2はnode.jsで動作するWebアプリケーションであり、そのWebアプリケーションに対して、Electrtonという技術を使ってデスクトップアプリケーションとして動作させています。つまりクラサバ構成ということになっています。 先程説明した時計や祝日カレンダー、天気予報、ニュースヘッドラインなどはすべてMagicMirror2のモジュールとして提供されているものを使用しています。YouTubeのライブ動画表示もモジュールとして提供されているものを使用しています。つまり各機能は全てモジュールという形で提供されており、そのモジュールを画面上の好きな位置に配置することで、デジタルサイネージの画面を構成しています。以下のようなイメージです。 このMagicMirror2を導入するハードウェアはnode.jsが動作するものであれば何でも良いのですが、Raspberry Piを使っている例が多いです。私はそのへんに転がっていたRaspberry Pi 3を使用しています。スペック的には十分です。 ディスプレイは何でもいいのですが、解像度よりも画面の大きさが重要です。とはいいつつも私はそんな大きなディスプレイを持っていなかったので、余っていた16インチのモバイルディスプレイを使っています。 導入手順 では、実際にMagicMirror2を導入する手順を説明します。 MagicMirror2のインストール Raspberry Piでもなんでもいいのですが、node.jsが動作するLinuxマシン(多分Windowsでも大丈夫)を用意します。Raspberry Piの場合はRaspberry Pi OSをインストールしておきます。 次に以下のコマンドを実行して、MagicMirror2をインストールします。pm2というnode.jsのプロセスマネージャも一緒にインストールします。これはつまり、マシンの電源を入れたときに自動的にMagicMirror2が起動するようにしたり、MagicMirror2を簡単に再起動したりするために使用します。 $ bash -c "$(curl -sL https://raw.githubusercontent.com/sdetweil/MagicMirror_scripts/master/raspberry.sh)" Do you want use pm2 (node process manager) for auto starting of your MagicMirror (y/N)? y Do you want to update the PM2 process name? (Default is MagicMirror) (y/N) N インストール自体はこれで終わりで、ディスプレイにMagicMirror2の画面が表示されると思います。 YouTubeモジュールのインストール 標準で備わっているモジュールもいくつかあるのですが、YouTubeのライブ動画を表示するモジュールは標準では備わっていないので、別途インストールします。以下のコマンドを実行します。 $ cd ~/MagicMirror/modules $ git clone https://github.com/nitpum/MMM-EmbedYoutube.git $ cd MMM-EmbedYoutube $ npm install スライドショーモジュールのインストール 背景の画像をスライドショーで表示するモジュールも標準では備わっていないので、別途インストールします。以下のコマンドを実行します。 $ cd ~/MagicMirror/modules $ git clone https://github.com/darickc/MMM-BackgroundSlideshow.git $ cd ~/MagicMirror/modules/MMM-BackgroundSlideshow $ npm install 直近の雨予報の自作モジュールのインストール これは私が作成したモジュールです。洗濯物を外に干しているときに、あと何時間後に雨が降るかがぱっとわかるようにするためのモジュールです。以下のコマンドを実行します。 $ cd ~/MagicMirror/modules $ git clone https://github.com/noriyukitakei/MMM-RainForecast.git $ cd MMM-RainForecast ちなみにVibe Codingで作成しました。コードは1行も書いていません。 https://github.com/noriyukitakei/MMM-RainForecast 設定ファイルの編集 MagicMirror2の設定ファイルは ~/MagicMirror/config/config.js にあります。このファイルを編集して、各モジュールの設定を行います。以下に私の設定ファイルの例を示します。 日本語表示 表示を日本語にするために、以下のように設定を変更します。 - language: "en", - locale: "en-US", // this variable is provided as a consistent location + language: "ja", + locale: "ja_JP.UTF-8", // this variable is provided as a consistent location カレンダーの設定 日本の休日カレンダーを表示するために、以下のように設定を変更します。 { module: "calendar", - header: "US Holidays", + header: "JP Holidays", position: "top_left", config: { calendars: [ { fetchInterval: 7 * 24 * 60 * 60 * 1000, symbol: "calendar-check", - url: "https://ics.calendarlabs.com/76/mm3137/US_Holidays.ics" + url: "https://calendar.webcal.jp/JapanHolidays.ics" } ] } }, YouTubeモジュールの設定 YouTubeのライブ動画を表示するために、以下のように設定を追加します。「video_id」には表示したいYouTube動画のIDを指定します。YouTubeのURLが https://www.youtube.com/watch?v=t9kwjZBLI-A の場合、video_idは t9kwjZBLI-A となります。 + { + module: 'MMM-EmbedYoutube', + position: 'bottom_bar', + config: { + video_id: 't9kwjZBLI-A', + autoplay:true, + loop: true, + width: 700, + height: 394 + }, + }, 直近の雨予報のモジュール設定 私自作の直近の雨予報モジュールを使用する場合は、以下のように設定を追加します。緯度(latitude)と経度(longitude)は自分の住んでいる場所に合わせて変更してください。 + { + module: "MMM-RainForecast", + position: "middle_center", // 好きな位置に + config: { + latitude: 35.681236, // 東京駅あたり + longitude: 139.767125, + maxHoursAhead: 12, // 12時間先までチェック + rainThreshold: 0.1, // 0.1mm/h 以上を「雨」とみなす + timezone: "Asia/Tokyo", + updateInterval: 10 * 60 * 1000, // 10分ごとに更新 + showDebug: false // trueにすると取得した生データも表示 + } + }, 他の部分は以下のGitHubリポジトリのREADMEを参考にしてください。 https://github.com/noriyukitakei/MMM-RainForecast MagicMirror2の再起動 以下のコマンドを実行して、MagicMirror2を再起動します。 $ pm2 restart all これで以下のように表示されるはずです。 まとめ 自宅にデジタルサイネージを導入するのいいです。もし自宅に使ってないRaspberry Piとかモニタが転がっている方はぜひ試してみてください。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 自宅にデジタルサイネージを導入しました first appeared on SIOS Tech Lab .
アバター
はじめに こんにちはSIOS Tech Labアドベントカレンダー11日目になります。私は現在KubeBlocksの調査検証をしており、それについての解説ブログをシリーズとして投稿しています。 第1回 はKubeBlocksについて解説を行い、 第2回 ではKubeBlocksでサポートされているDBソリューションについて解説を行いました。 今回からは実際にKubernetes環境にKubeBlocksを導入し、データベースの運用管理を自動化するサービスであるDBaaSを構築していきます。DBaaSについては こちらの記事 で詳しく解説をしているので興味のある方はぜひご覧ください。 また、今後の記事では、構築したDBaaS上でデータベースの作成やスケーリングなどの具体的な操作の解説も行っていく予定です。 今回は、KubeBlocksの導入手順について解説しますので、ぜひ最後までご覧ください。 導入環境構成図 以下の図は今回KubeBlocksを導入する環境の構成図です。今回の記事では赤い丸でマーキングされた範囲を対象としています。 今回の対象範囲は「KubeBlocksオペレーター」です。KubeBlocksオペレーターはKubernetesクラスタ内で、データベースのデプロイ・スケーリング・自己修復などの運用作業を自動的に実行するカスタムオペレーターです。 導入環境構成図 KubeBlocksの導入方法 KubernetesクラスタにKubeBlocksを導入する方法について、公式サイトでは以下の2つの方法が紹介されています Helm :本番環境に推奨されるインストール方法 kbcli  :検証や学習環境向きのインストール方法 今回は、この2つの導入方法をそれぞれ実行し、その手順を紹介します。 前提条件 Kubernetesクラスタがセットアップ済みであること kubectl コマンドが使用可能であること Helmがインストールされていること ( インストールガイド ) スナップショットコントローラがインストールされていること( インストールガイド ) kbcliインストール KubeBlocksのバージョンと一致させたバージョンのkbcliをインストールします。 今回はKubeBlocksv1.0.1をインストールするためkbcliも同様にv1.0.1をインストールします。 curl -fsSL https://kubeblocks.io/installer/install_cli.sh | bash -s v1.0.1 HelmによるKubeBlocks導入 HelmによるKubeBlocks導入を実施します。 CRDを追加する KubeBlocksが使用するカスタムリソース定義 (CRD) をKubernetesクラスタに登録します。これを行うことでKubeBlocksで提供される機能を利用することが出来るようになります。 kubectl create -f https://github.com/apecloud/kubeblocks/releases/download/v1.0.1/kubeblocks_crds.yaml # 出力例 customresourcedefinition.apiextensions.k8s.io/clusterdefinitions.apps.kubeblocks.io created customresourcedefinition.apiextensions.k8s.io/clusters.apps.kubeblocks.io created customresourcedefinition.apiextensions.k8s.io/componentdefinitions.apps.kubeblocks.io created # ~以下省略~ Helmリポジトリを追加する KubeBlocksのHelmチャートが格納されている外部リポジトリを、ローカルのHelm環境に登録しチャートを取得可能にするコマンドです。 helm repo add kubeblocks https://apecloud.github.io/helm-charts helm repo update # 出力例 "kubeblocks" already exists with the same configuration, skipping Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "piraeus-charts" chart repository ...Successfully got an update from the "kubeblocks" chart repository Update Complete. ⎈Happy Helming!⎈ KubeBlocksインストール KubeBlocksオペレーターをKubernetesクラスタにデプロイします。 helm install kubeblocks kubeblocks/kubeblocks --namespace kb-system --create-namespace --version=v1.0.1 # 出力例 NAME: kubeblocks LAST DEPLOYED: Mon Dec 8 13:46:15 2025 NAMESPACE: kb-system STATUS: deployed REVISION: 1 TEST SUITE: None インストール確認 kubeblocks-xxxxxxxxxx-xxxxx kubeblocks-dataprotection-xxxxxxxxxx-xxxxx の二つのPodがRunningになっていることを確認します。 kubectl get pods -n kb-system # 出力例 NAME READY STATUS RESTARTS AGE kubeblocks-777d976794-pfwlg 1/1 Running 0 5m16s kubeblocks-dataprotection-84db8c4c9-dmqx2 1/1 Running 0 5m16s snapshot-controller-58455ddb79-6nw4c 1/1 Running 0 9m1s kbcliによるKubeBlocks導入 kbcliによるKubeBlocks導入を実施します。 KubeBlocksインストール 以下のコマンドは、KubeBlocksの導入プロセス全体を自動化する単一のコマンドです。helmでは別コマンドで実行したCRDの適用、Helmリポジトリの追加、オペレーターのデプロイなどをkbcliではまとめて実行します。 kbcli kubeblocks install --version=1.0.1 --create-namespace # 出力例 KubeBlocks will be installed to namespace "kb-system" Kubernetes version 1.33.1 kbcli version 1.0.1 Collecting data from cluster OK Kubernetes cluster preflight OK Create CRDs OK Add and update repo kubeblocks OK Install KubeBlocks 1.0.1 OK Wait for addons to be enabled apecloud-mysql OK etcd OK kafka OK mongodb OK mysql OK postgresql OK redis OK KubeBlocks 1.0.1 installed to namespace kb-system SUCCESSFULLY! -> Basic commands for cluster: kbcli cluster create -h # help information about creating a database cluster kbcli cluster list # list all database clusters kbcli cluster describe <cluster name> # get cluster information -> Uninstall KubeBlocks: kbcli kubeblocks uninstall インストール確認 kubeblocks-xxxxxxxxxx-xxxxx kubeblocks-dataprotection-xxxxxxxxxx-xxxxx の二つのPodがRunningになっていることを確認します。 kubectl get pods -n kb-system # 出力例 NAME READY STATUS RESTARTS AGE kubeblocks-777d976794-vbl24 1/1 Running 0 4m40s kubeblocks-dataprotection-84db8c4c9-ppkcs 1/1 Running 0 4m40s snapshot-controller-58455ddb79-sks7q 1/1 Running 0 9m59s おわりに 今回はhelmとkbcliを利用してKubernetes上にKubeBlocksを導入する方法を紹介しました。 次回からは実際にKubeBlocksにデータベースを導入していきます。 参考文献 https://kubeblocks.io/docs/preview/user_docs/references/install-kbcli https://kubeblocks.io/docs/release-1_0/user_docs/overview/install-kubeblocks ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post KubeBlocks導入ガイド:Kubernetes上にDBaaSを構築する手順 first appeared on SIOS Tech Lab .
アバター
こんにちは、チンパンジー配属の永田です。 みなさんは「自分って、チンパンジーなんだ」と思ったことがありますか? 僕はあります。   新卒1年目のころ、「 サルでもわかるgit 」を読みました。 わかりませんでした。   「サルでもわかるgit」がわからないということは、サル以下ということになります。 すみません、見栄を張ってチンパンジーと偽っていましたが、実際はサル以下です。 当時は、自分がサル以下ということが受け入れられませんでした。 だから、数年前の自分を救うべく、今ここに「サル”以下”でもわかるgit」を記したいと思います。   ざっくり言うと グループで何かを作るとき、「誰がいつ何を変えたか」を全部記録してくれる仕組みです。 間違えても前の状態に戻せるし、メンバーが別々に作業しても後からきれいに合体できます。   例えば: 実際のグループ授業で起きがちなこと グループで協力し、一つのレポートを書いて提出すると想定してください。 よくある悲劇 田中「レポート最新版送るわ」 鈴木「え、俺も今書いてたんだけど」 山田「あれ、俺が昨日書いた部分消えてない?」 田中「ごめん、古いファイルに上書きしたかも…」 全員「どれが本当の最新版??」 「最新版.docx」「最新版(2).docx」「これが本当の最新.docx」が乱立している こうなってたら良かった レポートは一箇所で管理されてて、全員がそこにアクセスする 編集するときはオリジナルを編集せず、それぞれ自分用のコピーを作ってから作業する 作業が終わったら「これでOK?」とみんなに確認してから合体 もし何かミスっても、「昨日の状態に戻して」が一発でできる 誰かが編集したら「田中が第2章を追加しました」と記録が残る レポートでさえこの混乱なのに、プログラミングの仕事ではこれを何十人で、何万行のコードでやります。 毎日何十回も更新があって、しかも一文字間違えるだけでシステムが動かなくなるかもしれない。 だから「誰がいつ何を変えたか」を完璧に記録する仕組みが必須です。 これを実現するのがGit/GitHubです。   用語の説明 各用語の意味はざっくりこんな感じです。 用語 意味 リポジトリ 共有フォルダ。レポート本体や資料が全部入ってる場所 クローン 共有フォルダを自分のパソコンにダウンロードすること ブランチ 自分用のコピーを作って別々に作業する仕組み コミット 「ここまでやった」という保存記録。メモ付きで残せる プッシュ 自分の作業を共有フォルダにアップすること プルリクエスト 「これで合ってる?」と確認してから合体をお願いすること マージ 別々に作業した内容を一つに合体させること プル 最新版を自分のパソコンに取り込むこと コンフリクト 同じ場所を別々に編集しちゃって、どっちを採用するか決める必要がある状態   さっきの例を用語で言い換えると 理想の流れ 共有フォルダで原本レポートを一箇所で管理する 各メンバーが原本をダウンロード=手元にコピーを持つ 田中は念のため、その原本コピーをさらにコピー。「第2章作業用」という名前に変更し、編集を始める 作業が終わったらどこを誰が何のために編集したか、記録を残す 共有フォルダにアップする リーダーに「確認お願いします」と申請する OKが出たら本体に合体 他のメンバーは最新版をダウンロードしなおして、元の原本コピーに上書きする もし同じ場所を編集してしまっていたら、どっちを採用するか決める 用語で言い換えると リポジトリ で原本レポートを一箇所で管理する 各メンバーが クローン して手元にコピーを持つ 田中は「第2章作業」という ブランチ を新たに切って作業をはじめる 作業が終わったら コミット して記録を残す プッシュ して共有フォルダにアップする プルリクエスト でリーダーに確認をお願いする OKが出たら マージ して本体に合体 他のメンバーは プル して最新版を取り込む もし同じ場所を編集してたら コンフリクト を解決する   gitとgithub ややこしいのでここまでは一緒くたにしていましたが、gitとgithubは厳密には違います。 Git は自分のパソコンで動く「ファイルの変更履歴を記録するツール」です。 編集記録はもちろん、元の状態に戻したり、コピーを作って作業をはじめたりができます。 GitHub はその記録をネット上に保存して、みんなで共有できる「Webサービス」です。 原本と、その変更履歴を保存しているほか、みんながどういう変更を加えたか?とか、オリジナルへの合体の申請とかができます。   まとめ Git は、変更履歴を記録してくれる仕組み。自分のパソコンで動く。 GitHub は、それをネット上で共有できるサービス。みんなでアクセスできる。 要するに「誰が何を変えたか全部わかる」「前の状態に戻せる」「別々に作業しても大丈夫」という、グループ作業の悲劇を防ぐ道具です。 ちなみに「GoogleドキュメントやNotionと何が違う?」と思うかもしれませんが、それらは同時編集、Gitは「各自で作業して完成したら合体」という点で違います。 作りかけの状態で他の人を巻き込まないために、プログラミングではこっちが使われています。 以上、かなりざっくりとしたgit/githubの説明でした。   あとがき 僕が学んでいた当時に一番つまづいたのは、話のピンとこなさと用語の多さでした。 もう本当に、「アプリ開発の現場では、オフチョベットしたテフをマブガッドしてリットしています。」くらいわけがわかりませんでした。 なので今回は、大学生であればイメージしやすいグループ課題を具体例として、gitでやったらこんな感じ、を書いてみました。 このイメージがあった上でもう少し詳しくgitを学ぶと、わかりやすいんじゃないかと思います。   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post チンパンジーでもわかるGit/Github【初心者向け】 first appeared on SIOS Tech Lab .
アバター
久々のブログです。菊地啓哉です。 Dev Container は便利ですよね。開発を始めようとした時に、まずは Dev Container で環境をつくるのが習慣になってきました。 今回は(気持ちは)自力で Hardhat 3 で Solidity の開発をできる Dev Container の開発環境をつくっていこうと思います。つくり方の流れを説明しているので、これをベースにカスタマイズしていただければと思います。 ついでに、Hardhat 3 で SmartContract を動かすところまでやってみます。 前提 WSL上で Docker が使えること VS Code をインストール済みで、 Remote Development の拡張機能をインストール済みであること (パブリックネットワークにデプロイする場合)ガス代を払う為のネイティブトークンを持っている Wallet Address とその秘密鍵、RPC Endpoint 最終的にできあがる devcontainer.json ほとんど自動でつくられるもののままでとってもシンプルですが、できあがる devcontainer.json は以下の通りです。 // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node { "name": "Node.js & TypeScript", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "yarn install", // Configure tool-specific properties. "customizations": { "vscode": { "extensions": [ "NomicFoundation.hardhat-solidity" ], "settings": { "[solidity]": { "editor.formatOnSave": true } } } }, // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. "remoteUser": "node" } Dev Container で Solidity 開発環境をつくっていく まずは、WSL上で空の作業ディレクトリを作成し、VS Code のリモートエクスプローラーから、WSL に接続し、作業ディレクトリを開きます。 左下の背景色がある 「 >< WSL: ~」 と書かれているところをクリックして出てくるメニューから「コンテナーで再度開く」選びます。コマンドパレットから探して実行することもできます。 この先、環境によっては出てくるダイアログが違うかもしれないので参考程度に見ていただければと思いますが、 適当な starting point を選びます。Hardhat は Node.js が必要になり、TypeScript にも対応しているのでベースに「Node.js & TypeScript」を選びました。 Docker Image を選択します。特に理由が無ければ既定のもので良いと思います。 追加機能は必要なものがあれば選んで Enter または OKをクリックします。ここでは特に選択せずに OK にしました。 オプションファイルも必要であれば選んで進みます。ここも選択しませんでした。 これで、設定ファイルの devcontainer.json を .devcontainerディレクトリに作ってくれて、Dev Container で開発環境が開かれます。 Dev Container ができたということで、まず最初にターミナルで id を実行してユーザや UID/GID を確認しておきます。 UID/GID がホストの UID/GID と一致していれば、コンテナ内で作成したファイルをホストの WSL側で開けないなどの権限問題は起こらないのですが、 remoteUser に、このユーザを指定しておきます。 remoteUser を設定することで、Dev Container内で使用するユーザにホストの UID/GID が設定され、権限問題が起こらないようにしてくれるかと思います。 今の状態でログインしているユーザが root のような特権ユーザの場合には別のユーザを指定するなど、別の方法が必要になります。 Dev Container の設定を変更して、反映したいタイミングで左下の背景色がついている今度は「>< 開発コンテナー: ~」などになっているところをクリックして、「コンテナーのリビルド」を選び、リビルドします。適宜リビルドしてください。 もしくは、 devcontainer.json を変更した場合には右下などにポップアップが出てくると思いますので、そこからでもリビルドできます。 続いて、拡張機能を入れていきます。 通常、 VS Code でやるように、拡張機能のメニューから選んで追加したいものをインストールすれば使えますが、コンテナがリビルドされると入れ直しが必要になってしまうので、Dev Container の設定にも追加します。 ここでは Hardhat を作っている Nomic Foundation の Solidity 拡張を入れます。 拡張機能を見つけたらインストールして、歯車 から「拡張機能 ID のコピー」を選びます。 ※画面からインストールするのは、コンテナのリビルドを待つのが面倒だからです。 そして、devcontainer.json で customizations.vscode.extensions の配列の中に拡張機能 ID を追加します。補完機能を使って書いていけるので、IDはダブルクォーテーションで囲むことさえ気を付ければ、特に迷わず設定できると思います。 これでコンテナーのリビルドがあっても拡張機能が入った状態になります。上記の通り手動でインストールもしていればコンテナのリビルドは不要です。 続いて、Solidity ファイルを保存した時に、フォーマットされるように設定します。 こちらも、devcontainer.json で設定することで、コンテナ内にだけ設定が適用され、コンテナがリビルドされても設定が残るようにします。 具体的には、devcontainer.json で customizations.vscode.settings["[solidity]"]["editor.formatOnSave"] を true にします。 私が少し Solidity のコードをいじった感触としてはデフォルトの設定のままで特に問題無さそうだったので、スタイルの設定は特に設定しません。 拡張機能と自動フォーマットの設定を入れたものが以下のようになります。devcontainer.json のコードはこのページの最初に記載したものです。 これで簡易的ではありますが、Solidity の開発環境ができました。 Hardhat 3 で開発する 続いて、 Hardhat のチュートリアル に従って、Solidity の開発準備を進めていきます。 Hardhat 3 初期化 Dev Container で Node.js を使えるようにしているはずなので、以下のコマンドで初期化します。 チュートリアルには npm, pnpm, Yarn での実行方法が書かれているので、お好きなもので進めてください。ここでは、 npm で進めます。 npx hardhat --init 実行時点では Hardhat 3 はβ版となっていましたが、気にせず進んでいきます。幾つか質問されますが、適宜変更しつつ、進めていきます。(ここでは全てデフォルトでインストールしました。) 以下のようなディレクトリ構成となりました。 hardhat.comfig.ts :プロジェクトの設定。 Solidity のコンパイラのバージョン、ネットワーク設定、プラグインやプロジェクトで使用するタスクなどが設定されています。 contracts :Solidity の SmartContract を保存します。 .t.sol という拡張子で Solidity で書かれたテストファイルを保存することもできます。 test :TypeScript で書かれたテストを保存します。Solidity で書かれたテストファイルをここに保存することもできます。 ignition : SmartContract をどのようにデプロイするかを定義する Hardhat Ignition を保存します。また、デプロイ情報が保存されます。 scripts : ワークフローを自動化するスクリプトを保存します。スクリプトは Hardhat runtime にフルアクセスでき、プラグインの使用、ネットワークへの接続、コントラクトのデプロイなどができます。 Hardhat 3 の基本的な使い方 build npx hardhat build テスト Solidity で書かれているテスト(拡張子: .t.sol)と TypeScript で書かれたテストの全てが実行されます。 npx hardhat test # Solidity のテストだけ実行する場合は npx hardhat test solidity # TypeScript のテストだけ実行する場合は npx hardhat test nodejs ローカルで実行 まずはローカルの Hardhat node を起動します。 npx hardhat node Hardhat node が起動し、ログが出力されるようになります。続いて、Dev Container で別のターミナルを開き、初期化時に自動で作成された ignition/modules/Counter.ts を使って localhost のネットワークに Contract をデプロイします。 npx hardhat ignition deploy ignition/modules/Counter.ts --network localhost hardhat console プログラムから localhost ネットワーク上の Contract を操作しても良いのですが、ここでは対話型で Contract を操作してみます。 npx hardhat console --network localhost このコマンドを実行すると、対話型で Node.js のコマンドを実行できるようになります。ということで以下のようにいろいろと操作してみます。 // connection const connection = await hre.network.connect() // viem const viem = connection.viem // Contract Address // ignition/deployments/chain-31337/deployed_addresses.json か npx hardhat node のログからコピーする const address = "0x5fbdb2315678afecb367f032d93f642f64180aa3" // 例 // wallet const wallet = await viem.getWalletClient() // 先にデプロイしたContract const counter = await viem.getContractAt("Counter", address) // publicなプロパティの x を読み取る // public property に対応する view関数を勝手に作ってくれる await counter.read.x() // 5n // increment : x がインクリメントされる await counter.write.inc() // 再度読み取る await counter.read.x() // 6n Sepolia へのデプロイ デフォルトで作られている hardhat.config.ts では、ネットワーク設定の sepolia のところで、 configVariable というものが使われています。これは、Hardhat 3 が提供する、設定変数を扱うことのできる仕組みなので、これを使ってみましょう。 Sepolia の RPC Endpoint を設定します。 npx hardhat keystore set SEPOLIA_RPC_URL 初回の実行では設定するパスワードの入力が求められ、続けて打ち間違いが無いように再入力が求められます。その後、 RPC Endpoint として設定する値を入力します。 続いて、 Sepolia で処理を実行するための Wallet の秘密鍵を設定します。 npx hardhat keystore set SEPOLIA_PRIVATE_KEY パスワードを聞かれ、先ほどと同じ値を入力し、設定する値を入力します。 これで準備ができましたので、Sepolia にデプロイします。 npx hardhat ignition deploy ignition/modules/Counter.ts --network sepolia これで ignition のプログラムが実行され、Sepolia にデプロイされたかと思います。 まとめ Solidity 開発のために Dev Container 構築と Hardhat 3 の準備と簡単な使い方をご紹介しました。 Dev Container の設定についてはポチポチするのが中心で、あまり覚えたりコピペする必要が無いようになっているかと思います。 Hardhat は久しぶりに触ったら新しいものがいろいろありましたが、少し触った感覚だと使いやすい印象でした。ローカルのネットワークで簡単に SmartContract を動かせるので開発や検証に便利だと思います。 またかきます またね ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Hardhat 3 と Dev Container で Solidity の開発 first appeared on SIOS Tech Lab .
アバター
はじめに 前回はKubernetesのバックアップは、etcdとPV/PVCの二軸で、セットで行うことが重要であることを解説しました。しかし、ステートフルなアプリケーションのバージョンアップでは、データの互換性と整合性が課題となります。 本記事では、これらの複雑な課題を解消し、安全なリソースとデータのバックアップ・リストアを実現するソリューションである「Velero」について解説します。 Veleroの基本コンセプトとアーキテクチャ Velero(旧称 Heptio Ark)は、Kubernetesクラスターリソース(マニフェストファイル)と永続ボリューム(PV)のデータの両方をまとめてバックアップ/リストアを実現するツールです。 Kubernetesのバックアップでは、アプリケーションを構成するすべてのクラスターリソースをバックアップするだけでは不十分で、データ(永続ボリューム)も同時に保存する必要があります。これは、Veleroを使うことで実現可能です。 さらに、クラウドプロバイダーの変更やオンプレミスからクラウドへの移行、Kubernetesのメジャーバージョンアップに伴う新しいクラスターへのデータ移行といった複雑で時間がかかる作業もVeleroでは対応可能になります。 Veleroは以下の用途で利用できます。 クラスターのバックアップを取得し、データ損失が発生した場合にリストアを行う クラスターリソースを他のクラスターへ移行する 本番クラスターを開発/テストクラスターへ複製する Kubernetesのアップグレードなどのシステム操作を実行する前に、アプリケーションの状態をスナップショットする Veleroの主な特徴 クラスター内のすべてのオブジェクトをバックアップまたはリストアできる。オブジェクトタイプ、ネームスペース、ラベルによるフィルタリングも可能 バックアップ、リストア、スケジュールといったすべての操作の定義がKubernetesのカスタムリソースとして定義され、etcdに保存される クラウドプロバイダーまたはオンプレミスのKubernetes環境で動作可能 独自のカスタム機能をVeleroに追加できるプラグインシステムが提供されている PVのバックアップ方式 Veleroは、永続ボリューム(PV)のデータを保護するために、主に以下の3つの方式をサポートしています。ファイルシステムバックアップ(FSB)とスナップショットは、同一ボリュームに対して同時に実行されず、相互に排他的な関係になります。 方式 概要 主な用途 ボリュームスナップショット クラウドプロバイダー(AWS EBS, Azure Disk等)やCSIドライバーが提供するネイティブなスナップショット機能を利用する。 主要なクラウドプロバイダーやCSI準拠のストレージを利用している場合の標準的なデータ保護。 ファイルシステムバックアップ (FSB) Node Agent (Kopia Uploader) と呼ばれるDaemonSetが各ノードで稼働し、ボリュームのファイルシステムを直接読み取り、オブジェクトストレージにデータを保存する。 NFSのような共有ファイルシステムや、CSIドライバーが提供するスナップショット機能を持たないストレージのデータ保護。プロバイダー間の移行に利用可能。 CSIスナップショットデータムーバー CSIスナップショットで作成されたデータを、Node Agent経由でオブジェクトストレージに移動・コピーする。 クラウドプロバイダ間のデータ移行、オンプレミスからクラウドへのデータ移行、スナップショットデータの長期アーカイブ。 Veleroアーキテクチャ Veleroの主要リソースは以下の通りです。 バックアップ、リストア、スケジュールといった操作はクライアントのVelero CLIから実行します。 主要リソース 役割 実行環境 Velero サーバー メインコントロールプレーン。バックアップ/リストアのロジック、リソースの収集、オブジェクトストレージへの連携を担当する。 Kubernetesクラスター内のDeployment。 Node Agent ファイルシステムバックアップ(FSB)やCSIスナップショットデータムーバーなどのデータ転送を担う。 Kubernetesクラスター内のDaemonSet。 BackupStorageLocation (BSL) KubernetesリソースのメタデータやPVデータ(FSB/データムーバー利用時)の保存場所(オブジェクトストレージ)を定義する。 オブジェクトストレージ(AWS S3、Azure Blob、MinIOなど)。 VolumeSnapshotLocation (VSL) PVスナップショットの保存場所を定義。 CSIドライバー対応のスナップショットシステム。 バックアップのワークフロー VeleroによるKubernetesリソースと永続ボリュームのオンデマンドバックアップのワークフローは以下になります。 Image Source: https://velero.io/docs/v1.17/how-velero-works/ VeleroクライアントがKubernetes APIサーバーを呼び出してBackupオブジェクトを作成する BackupControllerが新しいBackupオブジェクトを認識して、検証を行う BackupControllerがバックアッププロセスを開始する。APIサーバーにリソースを照会してバックアップするデータを収集する 収集したオブジェクトをtar形式にアーカイブし、BackupControllerがオブジェクトストレージサービス(AWS S3など)を呼び出して、バックアップファイルをアップロードする 永続ボリューム(PV)が存在する場合、連携するストレージプロバイダのAPIを呼び出し、ボリュームのスナップショットを作成する フック(Backup Hooks)が設定されている場合、カスタムアクション処理の前(pre hook)または、すべてのカスタムアクション完了および追加アイテムのバックアップ完了後(post hook)に、Pod内のコンテナでコマンドが実行される スケジュールされたバックアップは、Cron式で指定された間隔で自動的に実行される Veleroのフック(Hook)機能とは? データベースのようなアプリケーションは、DBのバックアップ中にデータが書き換わると整合性が取れなくなる可能性があります。Veleroのフック(Hook)機能は、この問題を解決するために、バックアップ処理に合わせてコンテナ内で任意のコマンドを実行する機能です。例として、Veleroのフック機能は以下のようなことが可能です。 Pre-hook(直前):データの書き込みをロックし、静止点を作成 Post-hook(直後): バックアップ完了後にロックを解除し、通常稼働に復帰 Veleroでのリストア VeleroによるKubernetesリソースと永続ボリュームのリストアのワークフローは以下になります。 VeleroクライアントがKubernetes APIサーバーを呼び出してRestoreオブジェクトを作成する RestoreControllerが新しいRestoreオブジェクトを認識して、検証を行う RestoreControllerがオブジェクトストレージサービスからバックアップ情報を取得する。次に、バックアップされたリソースに対して前処理を行い、リソースが新しいクラスターで動作することを確認する RestoreControllerがリストアプロセスを開始する。依存関係を考慮した適切な順序で対象となるリソースが1つずつ復元される フック(Restore Hooks)が設定されている場合、以下のタイミングでリストアされるPod内のコンテナに対して実行される InitContainer:リストアされるPodにInitコンテナを追加して、アプリケーションコンテナが開始される前に必要なセットアップを実行する。PVと紐づく場合は、PVのリストア後に実行される Exec:リストアされたPodのコンテナが起動した後、コンテナ内でカスタムコマンドまたはスクリプトが実行される デフォルトではリストア時にターゲットクラスタ上のデータは削除されません。バックアップ内の同名リソースがターゲットクラスタ内に既に存在する場合は、そのリソースをスキップします。「update」フラグがある場合、リソースを更新します。 他のバックアップ手法との比較 VeleroはKubernetesネイティブなOSSバックアップソリューションです。他のKubernetesのバックアップソリューションとしては、Cohesity、Commvault、Rubrikが挙げられますが、いずれもエンタープライズ向け包括バックアップ製品の一機能としてKubernetesのバックアップ機能を提供しています。 Cohesity 初回以降は変更分のみをバックアップする永久増分バックアップを採用しており、バックアップ時間の短縮とネットワーク・ストレージ負荷の低減が強みです。 Commvault AKS/EKS/Openshiftなどのマルチクラウド、マルチディストリビューションのクラスターを1つの画面で統合管理できます。アプリ単体だけでなく、クラスタ全体を保護できる広範なバックアップが特徴です。 Rubrik 書き換え不可能な(不変)バックアップとゼロトラストアーキテクチャを採用し、ランサムウェア対策と整合性を提供しています。アプリとデータ状態の整合性を厳密に保ったままバックアップできる点が強みです。 Kubernetesだけを低コストでバックアップしたい場合はVeleroが第一候補に挙がります。既にCohesity、Commvault、Rubrikを使用している、またはKubernetes以外もバックアップ対象に含めたい場合は既存・導入予定のプラットフォームに寄せる方が現実的です。 まとめ 本記事では、Kubernetesのリソースと永続ボリュームを包括的に保護できるVeleroについて解説しました。Veleroは、Hook機能を利用してデータベースの整合性を確保できる点や、環境に応じてスナップショットとファイルシステムバックアップを使い分けられる柔軟性が強みです。 次回は、実際にVeleroをKubernetesへ導入するための構築手順と設定方法について詳しく解説します。 参考文献 https://velero.io/docs/v1.17/ https://github.com/vmware-tanzu/velero https://www.cohesity.com/ja-jp/solutions/kubernetes/ https://www.commvault.com/platform/kubernetes-backup https://www.rubrik.com/ja/solutions/kubernetes ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Kubernetesバックアップツール「Velero」の概要 first appeared on SIOS Tech Lab .
アバター
1. 今回の投稿について こんにちは、サイオステクノロジーの安藤 浩です。SIOS Tech Labアドベントカレンダー10日目の投稿です。 技術よりというよりマネジメントよりの内容で投稿します。私は開発も行いますが、プロジェクト管理を担当することがあり、プロジェクト管理で気を付けたいポイントを記載してみます。 ソフトウェア開発のプロジェクトでは、適切なプロジェクト管理が欠かせません。スケジュール、コスト、リスク、コミュニケーション、スコープ管理など様々な考慮をする必要があります。 特にWBS(Work Breakdown Structure)の作成はプロジェクト全体像の工数、タスクを把握するために重要な基盤です。 今回は、WBSの作成方法、スケジュール作成、JiraやNotionの比較をご紹介します。 2. WBS(Work Breakdown Structure)とは WBSはプロジェクトのタスクを階層的に分解し、管理可能な単位に整理する手法です。プロジェクトの成果物やタスクを「見える化」することで、以下のメリットが得られます: タスクの漏れ防止 :全体を分解することで、見落としがちなタスクを発見 正確な工数見積もり :小さな単位に分解することで精度向上 進捗管理の容易化 :各タスクの完了状況を明確に把握 責任の明確化 :誰が何を担当するかを明示(出来る限りタスクに対して1名のみを推奨) 3. WBS作成の基本ステップ 3.1. 成果物の洗い出し プロジェクトで作成すべき成果物を最初に洗い出します。 成果物の例 : 要件定義書 基本設計書 詳細設計書 ソースコード 単体テスト仕様書兼成績書 結合テスト仕様書兼成績書 リリース手順書 マニュアル・ドキュメント 3.2. タスクの分解 成果物の洗い出しと並行して、進めてもよいですが、成果物に対して必要なタスクを詳細に分解します。 分解の原則 : 1タスクは1~5人日程度の粒度にする → タスクが大きすぎると漏れや管理が困難になります。 具体的なタスクの完了条件を明確にする。→ タスクによっては完了条件を決めることが難しい場合がありますが、タスクの完了条件を決めることで対応内容を明確にします。 「○○の作成」「○○のレビュー」など動詞で終わる形にする。 → タスク名から何をするタスクか判別できるようにします。 担当者を1名で対応できるタスクに分割します。 → 複数担当者にわたる場合は、タスク分割が必要です。 WBS構造の例 : 担当やプロジェクト、会社によって異なると思いますが、3階層くらいまでにすることがWBS構造の把握をするためのポイントかと思います。 あまりに階層が深すぎたり、階層が浅すぎると工程やタスクがわかりにくくなります。 1. 要件定義フェーズ 1.1 要件ヒアリング 1.1.1 ヒアリングシート作成 1.1.2 ユーザーヒアリング実施 1.1.3 要件整理 1.2 要件定義書作成 1.2.1 機能要件定義 1.2.2 非機能要件定義 1.2.3 レビュー・承認 2. 設計フェーズ 2.1 基本設計 2.1.1 システム構成設計 2.1.2 画面設計 2.1.3 DB設計 2.2 詳細設計 ... 3.3. タスクの前後関係(依存関係)の定義 タスク間の依存関係を明確にすることで、どのタスクが完了していなければ着手できないのかの明確化や正確なスケジュール作成を行うことができます。 依存関係の種類 : プロジェクト管理 依存関係  を見ると 「PMBOKでは依存関係という用語は定義されていない」とあり、PMBOKでは依存関係という定義がないことを知りましたが、タスクの依存関係を意識するとスケジュールが立てやすいです。 種類 説明 例 FS(Finish to Start) 先行タスク完了後に後続タスク開始 設計完了後に実装開始 SS(Start to Start) 先行タスク開始と同時に後続タスク開始 設計書作成とレビュー準備を同時開始 FF(Finish to Finish) 先行タスク完了と同時に後続タスク完了 テスト実施とテスト報告書作成が同時完了 SF(Start to Finish) 先行タスク開始時に後続タスク完了 新システム稼働開始時に旧システム停止 依存関係の定義例 : 以下タスクがざっくりしていますが、こんな感じです。 タスクA(要件定義)→ タスクB(基本設計)[FS] タスクB(基本設計)→ タスクC(詳細設計)[FS] タスクC(詳細設計)→ タスクD(実装)[FS] タスクD(実装)→ タスクE(単体テスト)[FS] 3.4. タスクのバッファ設定 技術的に不確実性を抱えることは通常ですが、リスクに備えて各タスクにバッファ(余裕時間)を設定したり、各タスクではバッファを考慮せずに、全体の工数に対してバッファを積むことがあります。 ここでのタスクのバッファは工数見積もり時に考慮するもので、スケジュール上のバッファとは区別します。 タスクバッファの指針 : 各タスクに例: 5~20%の余裕を持たせる(プロジェクトによってどのくらいかも異なります。バッファを積まずに楽観的な工数とする場合もあります) 不確実性が高いタスクほど多めにバッファを確保 経験の浅いメンバーが担当するタスクは余裕を持たせる 例:実装タスクの工数見積もり ├── 機能A実装: 2人日 + バッファ0.5人日 = 2.5人日 ├── 機能B実装: 3人日 + バッファ0.5人日 = 3.5人日 └── 機能C実装: 4人日 + バッファ1人日 = 5人日 4. スケジュールの作成 WBSで洗い出したタスクをもとに、具体的なスケジュールを作成します。 月から金まであって「よし、5日だから5人日のタスクができるな!」となって失敗するケースがありますが、考慮すべき要素はいくつかあります。 スケジュール作成で考慮すべき要素 営業日(土日祝日、長期休暇など) スキル・経験 タスク優先度 バッファ 前工程、後工程の状況 稼働率 など 4.1. 稼働日を考慮したスケジュール作成 少なくとも営業日(稼働日)はどの会社にもあると思うので、スケジュールに織り込むことは必須です。 また、有休や稼働率の考慮なども必要なので、考慮すべき要素は以下かと思います。 考慮すべき要素 : 項目 内容 土日祝日 カレンダー上の休日を除外 年末年始・お盆 会社の休業期間 有給取得予定 メンバーの休暇予定 他プロジェクトとの兼務 稼働率の考慮(50%稼働など) 会議・定例 開発タスク以外の時間 スケジュール作成の際に毎回営業日いつだったか確認してSpreadsheet で営業日外(休日・祝日)一覧を書き出すのが面倒なので、直近やった方法を紹介しておきます。 前提 前提として、WBSには各工程のタスクの分割が行われ、タスクに対して工数が振られているとします。 No 工程 タスク 工数(人日) 1 設計 基本設計書作成 3 2 設計 詳細設計書作成 5 3 実装 機能A実装 2.5 4 実装 機能B実装 3.5 5 実装 機能C実装 5 6 テスト 単体テスト 3 7 テスト 結合テスト 4 手順 営業日の情報を入手する。YYYY-MM-dd の形式で一覧でスプレッドシート上で扱いやすければよいですが、カレンダー形式になっていたり、画像やPDFの場合があるので、 1の画像やPDFをGemini 3 Proに読み込ませて「祝日と休日すべてをYYYY-MM-dd の形式で一覧に出力して」とプロンプトを入力します。※弊社には有休奨励日が設定されている(休日と休日の間の営業日が多い)ので念のためその日は休む人がいそうなので考慮に入れておきます。 以下のような感じで出力してくれました。 **12月 (11日間)** 2025-12-06 2025-12-07 2025-12-13 2025-12-14 2025-12-20 2025-12-21 2025-12-27 2025-12-28 2025-12-29 2025-12-30 2025-12-31 ざっとあっていそうか確認してスプレッドシートに「休日」のシートを作成します。 3の結果を張り付けます。WBSの工数や納期によっていつまでの期間の情報が必要か異なります。 例えば2025/12/01がプロジェクト開始だとして、以下のようにC2のセルの開始日を「 =WORKDAY(WBS!F1 - 1, 1, '休日'!$B$4:$B$140) 」のようにすると休日でを避けて開始日を設定することができます。 7. D2セルの終了日は「 =WORKDAY(C2-1,E2+F2,'休日'!$B$4:$B$140) 」のようにして開始日からE2: 対応工数+F2: スケジュールバッファの期間での休日を除いた終了日が設定されます。 ※スケジュールバッファは以下で検討。 8. プロジェクトメンバーが複数いて並列対応が可能であれば、「並列対応」の列を用意してタスクを並列で進める考慮も行います。 9. 2026年1月中旬に終わりそうだとなります。 細かい作業ですが、休日一覧文字認識やフォーマットを変更したりするなども手間なので生成AIを活用して楽になりました。 4.2. スケジュールバッファの設定 プロジェクト全体やフェーズ単位で、期間的なバッファを設定します。タスクのバッファとは異なり、スケジュール上の調整日として確保します。結合テストの期間やリスクが見込まれるマイルストーンでは期間的なバッファを持たせることで例えばリリースに間に合わないということがないようにします。 スケジュールバッファの指針(例) : プロジェクトバッファ :全体期間の10~15%をプロジェクト終盤に確保(プロジェクトによってどのくらいかも異なります) マイルストーンバッファ :フェーズ終了時に調整日を設定 例:実装フェーズのスケジュール ├── 機能A実装: 1/6 ~ 1/14(6営業日) ├── 機能B実装: 1/15 ~ 1/18(4営業日) ├── 機能C実装: 1/19 ~ 1/25(5営業日) └── フェーズバッファ: 1/26 ~ 1/28(2営業日) ----------------------------------- 合計: 17営業日 4.3. ガントチャートによる可視化 ガントチャートは、作成したスケジュールを視覚的に表現するツールですが、Excel やスプレッドシートで書くと色づけするなど変更に耐えられないので、Backlog, Jira, Notion などのツールを使った方が良いと思います。 ガントチャートに含める情報 : タスク名 担当者 開始日・終了日 進捗率 見積工数(人日) 依存関係(矢印で表示) マイルストーン など ガントチャート作成ツールの例 : Microsoft Project Jira(タイムラインビュー) Notion(タイムラインビュー) Backlog プロジェクトメンバー全員で共通認識が容易にできることが重要だと思うので、Microsoft Projectはライセンスが高かったり、プロジェクトメンバー全員がMicrosoft Projectをもっていないとファイルが開けなかったりと導入には注意が必要です。 5. Jira と Notion の比較 直近だとJira(無料版) と Notionを利用しましたが、小~中規模ではNotionのほうが操作性が良く学習コストが低いと思いました。 Notionはやや操作が重くなることがありましたが、ステータスの変更によって進捗率の算出など数式を利用したいときはJiraの無料枠ではAutomation の月の上限がすぐに達してしまうのでうまくいきませんでした。 今回でだいぶJiraになれたので、次回機会があれば有料版も利用したいところです。 観点 Jira Notion 価格 有料(無料枠あり) 無料プランあり 得意な領域 アジャイル開発 ドキュメント管理、柔軟な運用 学習コスト やや高い 比較的低い カスタマイズ性 設定項目が豊富 自由度が非常に高い 開発ツール連携 GitHub, Bitbucket等と連携 API経由 チーム規模 中~大規模 小~中規模 WBSやガントチャートをJiraやNotionに落とし込む方法も記載しようと思いましたが、時間がないので次回にしたいと思います。 6. まとめ 本記事では、プロジェクト管理の基本であるWBS作成からスケジュール作成のポイント、Jira・Notionの比較についてご紹介しました。 1. WBS作成について : 成果物を洗い出し、タスクを適切な粒度(1〜5人日)に分解する タスクの依存関係を明確にする 不確実性に備えてタスクバッファを設定する 2. スケジュール作成について : 営業日(土日祝日、有給、稼働率)を正確に考慮する プロジェクト全体やフェーズ単位でスケジュールバッファを確保する ガントチャートで可視化し、進捗管理を容易にする 3. ツール選定について : Jiraはソフトウェア開発・アジャイルに強く、大規模チーム向け Notionは柔軟性が高く、ドキュメント管理も一元化したい小〜中規模チーム向け 7. 参考リンク プロジェクトマネジメント知識体系ガイド(PMBOK) プロジェクトマネジメント プロジェクト管理 依存関係 Jira公式ドキュメント Notion公式ドキュメント ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post プロジェクト管理入門 – WBS・スケジュール作成 first appeared on SIOS Tech Lab .
アバター
「SIOS社員が今年一年で学んだこと」アドベントカレンダー9日目です。 最近少し苦戦した、Kongの小ネタを紹介させていただきます。 想定状況 旧サービスから新サービスに移行するにあたって、まずは一部のユーザーにのみ公開し動作を確認してから全体公開したい…という状況を考えます。 旧サービス: http://httpbin.org/xml 新サービス: http://httpbin.org/json こういった作業を本番で作業を行う場合はdecKコマンドを叩くと思いますが、今回は分かりやすさ重視でKong Manager上からポチポチ設定していく手順を紹介します。 また、canary release pluginはenterprise onlyのため、順当な手段で試そうとするとハードルが高いです。幸い Kong academy 内で実際のKongの操作を試せるvirtual labではenterprise onlyなpluginでも使うことができるので、そちらを使わせていただきましょう。 操作手順 workspace作成 適当なworkspaceを作ります。複数のworkspace作成もenterprise機能だった気が… serviceの作成 Gateway Servicesから、旧サービスとなるhttp://httpbin.org/xmlを割り当てたcanary-api-serviceを作成します。 Name: canary-api-service Full URL: http://httpbin.org/xml routeの作成 上記のserviceに紐づいたrouteを作成します。 Name: canary-api-route Service: canary-api-service Path: /api/canary 疎通確認 curl -i http://localhost:8000/api/canary HTTP/1.1 200 OK Content-Type: application/xml Content-Length: 522 Connection: keep-alive Date: Sat, 06 Dec 2025 11:55:35 GMT Server: gunicorn/19.9.0 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true X-Kong-Upstream-Status: 200 X-Kong-Upstream-Latency: 2009 X-Kong-Proxy-Latency: 2 Via: 1.1 kong/3.10.0.6-enterprise-edition <?xml version='1.0' encoding='us-ascii'?> <!-- A SAMPLE set of slides --> <slideshow title="Sample Slide Show" date="Date of publication" author="Yours Truly" > <!-- TITLE SLIDE --> <slide type="all"> <title>Wake up to WonderWidgets!</title> </slide> <!-- OVERVIEW --> <slide type="all"> <title>Overview</title> <item>Why <em>WonderWidgets</em> are great</item> <item/> <item>Who <em>buys</em> WonderWidgets</item> </slide> </slideshow> key auth pluginを設定 routeに対してpluginを適応します。 Scoped Route: canary-api-route consumerを作成 旧サービスを見せるか新サービスを見せるか分類するため、2つのconsumerを作成します。 Username: general-consumer 同様に、Username: vip-consumerでvip-consumerを作成します。 key auth credential付与 それぞれのconsumerにcredentialを付与します。 general-consumerはgeneral-apiを割り当てます 同様に、vip-consumerにはvip-apiを割り当てます。 疎通確認 apikeyがない場合、401で弾かれます。 curl -i http://localhost:8000/api/canary HTTP/1.1 401 Unauthorized Date: Thu, 06 Nov 2025 02:13:07 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive WWW-Authenticate: Key realm="kong" Content-Length: 96 X-Kong-Response-Latency: 5 Server: kong/3.4.3.21-enterprise-edition { "message":"No API key found in request", "request_id":"e9f5080d632bba08e2ba023597c3d006" } 先ほど設定したapikeyがあれば、アクセスが可能です。 curl -i http://localhost:8000/api/canary?apikey=general-api curl -i http://localhost:8000/api/canary?apikey=vip-api HTTP/1.1 200 OK (以下略) acl pluginを設定 Scoped Route: canary-api-route Allow: general-acl, vip-acl acl credentialを付与 各consumerにacl credentialを付与します vip-consumerに対しても同様に、vip-aclを設定します。 canary pluginを設定 以下の通り設定します。 Scoped Route: canary-api-route UpstreamHost : httpbin.org UpstreamPort : 80 UpstreamUri : /json Groups : vip-acl Hash: allow 疎通確認 これで、general-consumerは旧サービス(/xml)が見え、vip-consumerは新サービス(/json)が見えるようになりました。 curl -i http://localhost:8000/api/canary?apikey=general-api HTTP/1.1 200 OK Content-Type: application/xml Content-Length: 522 Connection: keep-alive Date: Sat, 06 Dec 2025 11:55:35 GMT Server: gunicorn/19.9.0 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true X-Kong-Upstream-Status: 200 X-Kong-Upstream-Latency: 2009 X-Kong-Proxy-Latency: 2 Via: 1.1 kong/3.10.0.6-enterprise-edition <?xml version='1.0' encoding='us-ascii'?> <!-- A SAMPLE set of slides --> <slideshow title="Sample Slide Show" date="Date of publication" author="Yours Truly" > <!-- TITLE SLIDE --> <slide type="all"> <title>Wake up to WonderWidgets!</title> </slide> <!-- OVERVIEW --> <slide type="all"> <title>Overview</title> <item>Why <em>WonderWidgets</em> are great</item> <item/> <item>Who <em>buys</em> WonderWidgets</item> </slide> </slideshow> curl -i http://localhost:8000/api/canary?apikey=vip-api HTTP/1.1 200 OK Content-Type: application/json Content-Length: 429 Connection: keep-alive Date: Sat, 06 Dec 2025 12:02:41 GMT Server: gunicorn/19.9.0 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true X-Kong-Upstream-Status: 200 X-Kong-Upstream-Latency: 1530 X-Kong-Proxy-Latency: 3 Via: 1.1 kong/3.10.0.6-enterprise-edition { "slideshow": { "author": "Yours Truly", "date": "date of publication", "slides": [ { "title": "Wake up to WonderWidgets!", "type": "all" }, { "items": [ "Why <em>WonderWidgets</em> are great", "Who <em>buys</em> WonderWidgets" ], "title": "Overview", "type": "all" } ], "title": "Sample Slide Show" } } 本リリース vip-consumerに対してカナリアリリースを行い、十分に動作検証ができたとします。canary release状態から通常リリースに変更するには、serviceに登録しているendpointを新サービスのものに変更し、canary release pluginを削除すればOKです いかがでしたか? 長々とした拙筆にお付き合いいただきありがとうございました。本記事が皆様の、何かしらの助けになれば幸いです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【Kong初心者向け】Canary Release Pluginの使い方 first appeared on SIOS Tech Lab .
アバター
はじめに 前回はダウンタイムを最小限に抑えるBlue/Greenデプロイ戦略について紹介しました。これは旧環境(Blue)と新環境(Green)を完全に分離して用意し、外部からのトラフィックを一瞬でGreenに切り替える手法です。これにより、ダウンタイムを抑制しつつバージョンアップを完了させ、かつ問題発生時の切り戻し(ロールバック)も瞬時に行えるという、安全性の高い方法です。 本記事では、安全なバージョンアップに不可欠なバックアップの必要性と、その際に直面するデータ管理の課題について深堀して解説します。 なぜKubernetesのリソースバックアップが必要なのか バージョンアップ中の操作ミスやエラーにより、Kubernetesでは以下の二つの要素が失われる可能性があります。 クラスターリソースの設計図:Deployment、Serviceなどクラスター全体を構成する設定情報 アプリケーションデータ:データベースに保存されたアプリケーションデータなど サービスを元の状態に完全に復元するには、アプリケーションデータに加え、クラスターの設計図も完全に復元できる状態が必要です。 ステートレスとステートフルアプリケーションの違い デプロイメント戦略を考えるうえで、データの有無が大きな違いとなります。 ステートレス:データを持たず、リソースの入れ替えが容易です。バージョンアップ時にデータ移行の問題は発生しません。 ステートフル:永続的なデータ(例:DBのデータ)を保持し、その状態に依存して動作します。データの損失を防ぎつつ、新旧バージョン間でデータの互換性をどう担保するかが大きな壁となります。 Kubernetesのデータ構成要素 Kubernetesが「データ」をどのように管理しているか、バックアップとリストアに必要な要素を解説します。 etcd Kubernetesクラスターの全てのメタデータと状態を保持しています。 etcdのバックアップこそがクラスターの設計図のバックアップであり、これがなければPodやServiceの定義は全て失われてしまいます。etcdのバックアップは最も重要です。 PV、PVC(アプリケーションの永続データの実体) PVC(Persistent Volume Claim): アプリケーションが「ストレージを使いたい」と要求するリソース定義です。 PV(Persistent Volume): 実際のストレージ(ディスクなど)の実体です。 アプリケーションデータを復元するには、PVの実データだけでなく、そのデータを使うためのPVCというKubernetesリソース定義もセットでリストアしなければなりません。この「リソースとデータの実体をまとめて管理する」点が、従来のバックアップとの大きな違いです。 Blue/Greenにおけるデータ移行の課題 ステートフルなアプリケーションの安全なバージョンアップにおいて、バックアップ・リストアが課題になる箇所を説明します。 課題1:ロールバック時のデータ損失 Blue/GreenデプロイでデータをコピーしてGreen環境を構築した場合、ロールバックでBlue環境に戻ると、Green環境で発生した新規データは全て失われます。 技術的には「コピーした時点に戻す」という期待通りの動作ですが、これはデータ損失を意味します。 最も問題なのは、ロールバック後に改めてバージョンアップを試みる際、失われたデータは二度と取り戻せないという点です。 安全なロールバックを実現するには、このデータ損失を防ぎつつ、リソースとデータを同時に、任意の時点に復元する必要があります。 課題2:新旧バージョンのデータ互換性 Blue/Greenデプロイでデータストアを共有した場合、新バージョン(Green)がDBスキーマを変更すると、即座に旧バージョン(Blue)のアプリケーションが動かなくなります。 バックアップツールは「データの互換性」そのものを解決できません。データ移行処理(DBマイグレーション)を、デプロイプロセスの中に組み込む必要があり、この統合が複雑になります。 安全なバージョンアップを実現するには、これらの課題を解消するために、リソースとデータを同時に扱える専門的なツールが必要になります。 まとめ 今回の記事では、Kuberntesのバックアップは、etcdとPV/PVCの二軸で、セットで行うことが重要であることを解説しました。しかし、ステートフルなアプリケーションのバージョンアップでは、データの互換性と整合性が課題となります。 これらの複雑な課題を解消し、安全なリソースとデータのバックアップ・リストアを実現するにはKubernetes専門のバックアップツールが不可欠です。次回は、そのソリューションである「Velero」について解説します。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 初めてのKubernetesバージョンアップ:Kubernetesにおけるバックアップの必要性とデータ管理の課題 first appeared on SIOS Tech Lab .
アバター
はじめに 皆さん、こんにちは!PS-SLの織田です。 SIOS Tech Labアドベントカレンダー8日目になります!今回は、『 Java言語で学ぶデザインパターン入門 』の第1章を読んだ感想をまとめていきたいと思います。購入してからそこそこ時間が経ってしまったのですが、なんとか第1章を読むことができたので内容をまとめていきたいと思います。 Iteratorパターンとは 第1章ではIteratorパターンに関する内容が記されていました。Iteratorパターンとは何かしらの集合があったときに、それらを順に指していき 処理を繰り返し実行 することです。文字で説明しても何のこっちゃという感じなので、具体的なコードとともに説明していきます。 基本要素:Book.java public class Book { private String name; public Book(String name) { this.name = name; } public String getName() { return name; } } このクラスは単純なデータホルダーです。本の名前を保持するprivateフィールドと、それを取得するgetName()メソッドを提供します。コレクションに格納される個々の要素を表現する役割を担います。Iteratorパターンにおいては「要素」の役割を果たし、パターン全体の基盤となるシンプルなクラスです。 集約オブジェクト:BookShelf.java import java.util.Iterator; public class BookShelf implements Iterable<Book> { private Book[] books; private int last = 0; public BookShelf(int maxsize) { this.books = new Book[maxsize]; } public Book getBookAt(int index) { return books[index]; } public void appendBook(Book book) { this.books[last] = book; last++; } public int getLength() { return last; } @Override public Iterator<Book> iterator() { return new BookShelfIterator(this); } } 本棚を表現するクラスで、Iteratorパターンの中核となる「集約」の役割を担います。内部では固定サイズの配列を使って本を管理し、本の追加(appendBook)、指定位置の本の取得(getBookAt)、現在の本の数を取得(getLength)といった基本機能を提供します。 反復子:BookShelfIterator.java import java.util.Iterator; import java.util.NoSuchElementException; public class BookShelfIterator implements Iterator<Book> { private BookShelf bookShelf; private int index; public BookShelfIterator(BookShelf bookShelf) { this.bookShelf = bookShelf; this.index = 0; } @Override public boolean hasNext() { if (index < bookShelf.getLength()) { return true; } else { return false; } } @Override public Book next() { if (!hasNext()) { throw new NoSuchElementException(); } Book book = bookShelf.getBookAt(index); index++; return book; } } 実際の反復処理を担当するクラスです。BookShelfへの参照と現在の位置を示すindexフィールドを持ち、hasNext()で次の要素の存在を判定し、next()で要素を順次返します。 このクラスの重要な点は、BookShelfの内部構造を知らずに反復処理を行えることです。getLength()とgetBookAt()メソッドを通じてのみBookShelfにアクセスし、直接配列を操作することはありません。 利用例:Main.java import java.util.Iterator; public class Main { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(4); bookShelf.appendBook(new Book("Around the World in 80 Days")); bookShelf.appendBook(new Book("Bible")); bookShelf.appendBook(new Book("Cinderella")); bookShelf.appendBook(new Book("Daddy-Long-Legs")); // 明示的にIteratorを使う方法 Iterator<Book> it = bookShelf.iterator(); while (it.hasNext()) { Book book = it.next(); System.out.println(book.getName()); } System.out.println(); // 拡張for文を使う方法 for (Book book: bookShelf) { System.out.println(book.getName()); } System.out.println(); } } Iteratorパターンの使用方法を実演するクライアントクラスです。BookShelfインスタンスを作成し、複数の本を追加した後、二つの異なる方法で反復処理を行います。 一つ目は明示的にiterator()メソッドを呼び出してIteratorを取得し、while文でhasNext()とnext()を使った伝統的な方法です。二つ目はJava 5以降で導入された拡張for文を使った方法で、Iterableインターフェースの実装により自動的に内部でIteratorが使用されます。 いずれにしても繰り返し処理の中ではIteratorのメソッドのみ呼び出されています。ここは伏線なので覚えておいてください。 Iteratorパターンで嬉しいこと 一見すると、冗長な書き方に見えるかもしれませんが、このパターンを使うことで受けられる恩恵があります。例えば、現在のBookShelfクラスは配列で管理をしているため、最初に指定した本棚の大きさ以上のデータは入れられません。そこで、配列ではなくjava.util.ArrayListを使うよう修正するとします。こうなると、「複数のファイルにまたがって修正を実施しなきゃいけないのか…」と思うかもしれませんが、実はBookShelfクラスだけ修正すれば大丈夫です。 BookShelf.java(修正後) import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class BookShelf implements Iterable<Book> { private List<Book> books; public BookShelf(int initialsize) { this.books = new ArrayList<>(initialsize); } public Book getBookAt(int index) { return books.get(index); } public void appendBook(Book book) { books.add(book); } public int getLength() { return books.size(); } @Override public Iterator<Book> iterator() { return new BookShelfIterator(this); } } 先述の通り、Mainの繰り返し処理の中ではIteratorのメソッドのみ呼び出されています。つまりBookShelfクラスに依存していないため修正も不要ということです。 もしiteratorパターンを使っていない状況で、配列からjava.util.Listへの修正を行った場合、main関数の繰り返し処理は以下のように変更する必要があります。 Main.java(配列版) public class Main { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(4); bookShelf.appendBook(new Book("本A")); bookShelf.appendBook(new Book("本B")); // 配列を取得して処理 Book[] books = bookShelf.getBooks(); for (int i = 0; i < bookShelf.getLength(); i++) { System.out.println(books[i].getName()); } } } Main.java(List版) import java.util.List; public class Main { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(4); bookShelf.appendBook(new Book("本A")); bookShelf.appendBook(new Book("本B")); // Listを取得して処理 List<Book> books = bookShelf.getBooks(); // Book[]からList<Book>に変更 for (int i = 0; i < books.size(); i++) { // getLength()からsize()に変更 System.out.println(books.get(i).getName()); // books[i]からget(i)に変更 } } } 上記のコードの通りMain.javaで複数箇所の修正が必要になり、手間がかかるだけでなく、コンパイルエラーが発生する可能性もあります。 import文の追加 変数型の変更 メソッド呼び出しの変更 まとめ 第1章を読んだ感想としては、「デザインパターンを意識しなくてもコード を書くのはなんとかなりそう。ただ、可読性や保守性はめっちゃ低いなぁ」という感じでした。例えるなら、きれいに整えられた回路(下図①)と、ただ闇雲にジャンク品を使いながら無計画に作られた回路(下図②)のような具合です。デザインパターンを理解していなくても動くものは作れるでしょう。しかし、作りたいものが複雑になればなるほど、デザインパターンなしでは保守・運用の難易度が跳ね上がります。まだまだ読み始めたばかりですが、今後もデザインパターンを学び、保守・運用のしやすいコードを実際の業務でも書けるように頑張りたいと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post デザインパターンのすゝめ ~Iteratorパターン編~ first appeared on SIOS Tech Lab .
アバター
こんにちは、伊藤です。 この記事は、アドベントカレンダー7日目の記事になります。 今回は、Exchange Onlineで、メールの自動転送を制限する方法を紹介します。 Exchange Onlineでは特定のユーザー・グループ・ドメインに対して自動転送可能なメールドメインを制限することが可能です。 今回はその中でも 特定のドメインメールのユーザーに対してメール自動転送を不可にする方法 、 特定のドメインメールのユーザーに対してメール自動転送可能ドメインを制限する方法 を紹介します。 メールの自動転送を制限する目的 メールの自動転送を制限する主な目的は、メールに含まれる情報の外部漏洩を軽減することです。メールでは、ファイルやパスワードのやり取りを行うことがありますが、自動転送を制限しない場合、全てのドメインのメール宛てに転送可能になるため、情報漏洩のリスクが高まります。 設定に必要なMicrosoft Entra IDのロールについて 今回紹介する設定を行うためには、「Exchange管理者」、「セキュリティ管理者」ロールを持つMicrosoft Entra IDのアカウントが必要です。 特定のドメインメールのユーザーに対してメール自動転送を不可にする 例として検証ドメイン(soito001.mail.onmicrosoft.com)のユーザに対してメール自動転送を不可にします。 アウトバウンド スパム フィルター ポリシーの設定 1. Microsoft 365 Defender ポータル(https://security.microsoft.com/)に管理者アカウントでサインインします。 2. [メールとコラボレーション] > [ポリシーとルール] > [脅威ポリシー] > [スパム対策] の順に選択します。 3. [スパム対策ポリシー] ページで、メール自動転送を制限したいドメイン(例:soito001.mail.onmicrosoft.com) 専用のカスタムポリシーを作成します。[+ ポリシーの作成] > [Outbound] の順に選択します。 4. ポリシーの名前を設定します(例: soito001.mail.onmicrosoft.com Auto-forward Policy)。 5. [ユーザー、グループ、およびドメイン] で、このポリシーを適用する対象として、[ドメイン] に”soito001.mail.onmicrosoft.com”を指定します。特定のユーザー、グループに対して適用したい場合は、それぞれ[ユーザー] 、[グループ]で指定してください。 6. [送信の保護設定]で、[自動転送ルール] に「オフ – 転送が無効になっています」を設定します。 7. 確認画面にて適用するポリシーを確認し、[作成]を選択します。 自動転送の制限を確認する 1. テストアカウント(exchangetest001@soito001.mail.onmicrosoft.com)の自動転送を有効にして、テストアカウントにメールを送信します。 2. Exchange 管理センター (EAC)(https://admin.exchange.microsoft.com/)に管理者アカウントでサインインします。 3. [メールフロー] > [メッセージ追跡] > [+ 追跡を開始] の順に選択します。 4. [新しいメッセージ追跡]で、[受信者]にテストアカウントを設定して[検索]を選択します。時間の範囲等の条件で絞り込むことも可能です。 5. テストアカウントへのメール送信に該当する追跡結果を確認し、[メッセージイベント]で外部転送がブロックされている内容を確認します。 特定のドメインメールのユーザに対してメール自動転送可能ドメインを制限する 例として検証ドメイン(soito001.mail.onmicrosoft.com)のユーザに対して社内ドメインのみへのメール自動転送を許可します。 アウトバウンド スパム フィルター ポリシーの設定 1. Microsoft 365 Defender ポータル(https://security.microsoft.com/)に管理者アカウントでサインインします。 2. [メールとコラボレーション] > [ポリシーとルール] > [脅威ポリシー] > [スパム対策] の順に選択します。 3. [スパム対策ポリシー] ページで、メール自動転送を制限したいドメイン(例:soito001.mail.onmicrosoft.com) 専用のカスタムポリシーを作成します。[+ ポリシーの作成] > [Outbound] の順に選択します。 4. ポリシーの名前を設定します(例: soito001.mail.onmicrosoft.com Auto-forward Policy)。 5. [ユーザー、グループ、およびドメイン] で、このポリシーを適用する対象として、[ドメイン] に”soito001.mail.onmicrosoft.com”を指定します。特定のユーザー、グループに対して適用したい場合は、それぞれ[ユーザー] 、[グループ]で指定してください。 6. [送信の保護設定]で、[自動転送ルール] に「オン – 転送が有効になっています」を設定します。 7. 確認画面にて適用するポリシーを確認し、[作成]を選択します。 リモートドメインの設定 1. Exchange 管理センター (EAC)(https://admin.exchange.microsoft.com/)に管理者アカウントでサインインします。 2. [メール フロー] > [リモート ドメイン] の順に選択します。 3. ここで、許可するドメイン と 既定(その他すべて) の設定を行います。     A. 許可する外部ドメインの設定     [+ リモート ドメインを追加] をクリックします。     [ドメイン名を指定]で、[リモートドメイン]に社内ドメインを入力します。     [メールの返信の種類] で、「自動転送を許可する」 (Allow automatic forwarding) を有効にします。    確認画面にて適用するリモートドメインの設定を確認し、[保存]を選択します。     B. 既定ドメインの設定 (許可されていないその他すべてのドメイン)     リモート ドメインの一覧から、「Default」または * (アスタリスク) という名前の既定のリモート ドメインを見つけ、[返信の種類を編集]を選択します。     「自動転送を許可する」 (Allow automatic forwarding) を無効にして保存します。 自動転送の制限を確認する 1. テストアカウント(exchangetest001@soito001.mail.onmicrosoft.com)の自動転送を有効にして、[メールの転送先]に社内ドメインのメールアドレスを指定し、テストアカウントにメールを送信します。 2. 社内ドメインのメールアドレスへの転送は許可されているため、社内ドメインのメールアドレスで転送メールを受信することができます。 3. Exchange 管理センター (EAC)(https://admin.exchange.microsoft.com/)のメッセージ追跡機能にて、テストアカウントへのメール送信に該当する追跡結果を確認し、[メッセージイベント]で外部転送が完了した内容を確認します。 4. テストアカウント(exchangetest001@soito001.mail.onmicrosoft.com)の[メールの転送先]に社内ドメイン以外のメールアドレスを指定し、テストアカウントにメールを送信します。 5. Exchange 管理センター (EAC)(https://admin.exchange.microsoft.com/)のメッセージ追跡機能にて、テストアカウントへのメール送信に該当する追跡結果を確認し、[メッセージイベント]で外部転送がブロックされている内容を確認します。 特定のドメインメールのユーザーに対してメール自動転送を不可にする方法 で確認したメッセージの内容とは異なりますが、イベント: Dropはメールの配送がここで 破棄(Drop) されたことを示しており、”handled AutoForward addressed to external recipient”は、外部受信者宛の自動転送(AutoForward)として処理されたことを示しております。外部への自動転送の設定で禁止されているからここで破棄するという挙動になります。 まとめ 今回は、Exchange Onlineで、 特定のドメインメールのユーザーに対してメール自動転送を不可にする方法 、および 特定のドメインメールのユーザーに対してメール自動転送可能ドメインを制限する方法 を紹介しました。 Exchange Onlineの設定の参考にしていただければ幸いです。 参考 参考 Microsoft 365 での外部メール転送の構成と制御 – Microsoft Defender for Office 365 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Exchange Onlineのメール自動転送を制限する first appeared on SIOS Tech Lab .
アバター
アドベントカレンダー6日目の記事です。 今回はClaude Codeを使っていて「毎回同じ説明をするのが面倒」「プロジェクト固有のルールを覚えさせたい」という問題を解決する方法を紹介します。 また今回Web開発に使えそうな汎用Skillsのテンプレートを作成し、Githubで公開しましたのでぜひ本記事を読む際に参考にしていただき、よりよいスキルセットがあればPRお待ちしています。 https://github.com/atomic-kanta-sasaki/claude-code-general-skills/tree/main/.claude/skills Skillsとは何か? Skillsは、Claudeに特定のタスクの実行方法を教えるためのナレッジパッケージです。 公式ドキュメントでは以下のように説明されています: Skillsはフォルダ内の指示、スクリプト、リソースで、Claudeが特定のタスクを繰り返し実行する方法を教えます。 簡単に言えば、 新しいチームメンバーに渡すオンボーディング資料 のようなものです。プロジェクトの規約、ツールの使い方、ワークフローを文書化しておけば、Claudeがそれを参照して作業してくれます。 Skillsの特徴 自動呼び出し : ユーザーが明示的に指定しなくても、タスクに応じてClaudeが自動で適切なスキルを選択 プログレッシブ・ディスクロージャー : 必要な情報だけを段階的に読み込むため、コンテキストを圧迫しない コード実行可能 : 指示だけでなく、Pythonスクリプトなども含められる Skillsとサブエージェント・CLAUDE.mdの違い Claude Codeには似たような機能がいくつかあります。違いを整理しておきましょう。 機能 目的 トリガー コンテキスト Skills 知識・手順の提供 自動(description基準) メインと共有 Subagents タスクの委任・並列処理 自動/手動 独立 CLAUDE.md プロジェクト全体のコンテキスト 常時読み込み メインと共有 Commands 定型プロンプト実行 手動(/command) メインと共有 使い分けの指針 Skills : 特定タスク(レビュー、テスト作成など)の専門知識 Subagents : 独立したコンテキストで並列作業させたい場合 CLAUDE.md : プロジェクト全体で常に参照すべき情報 Commands : よく使うプロンプトのショートカット Skillsのディレクトリ構造 Skillsは以下の場所に配置します: .claude/skills/ └── your-skill-name/ ├── SKILL.md # 必須:メインの指示ファイル ├── reference.md # 任意:参照ドキュメント ├── examples.md # 任意:使用例 ├── scripts/ # 任意:ヘルパースクリプト │ └── helper.py └── templates/ # 任意:テンプレートファイル └── template.txt 配置場所による違い 場所 スコープ ~/.claude/skills/ 全プロジェクトで使用可能(個人用) .claude/skills/ プロジェクト固有(チーム共有可能) SKILL.md の書き方 基本構造 --- name: your-skill-name description: | このスキルが何をするか、いつ使うべきかの説明。 具体的なトリガーワードや使用シーンを含める。 version: 1.0.0 --- # Your Skill Name ## Overview このスキルの概要説明 ## Instructions ステップバイステップの指示 ## Examples 具体的な使用例 フィールドの説明 フィールド 必須 制限 説明 name 64文字、小文字・数字・ハイフンのみ スキルの識別子 description 1024文字 最重要 : いつ呼び出すかの判断基準 version 任意 – バージョン管理用 descriptionの書き方(最重要ポイント) Skillsが正しく呼び出されるかどうかは、 descriptionの書き方で9割決まります 。 Claudeはdescriptionを見て「このスキルを使うべきか」を判断するため、曖昧な記述では呼び出されません。  悪い例 description: コードを手伝う これでは「いつ」「何を」手伝うのかわかりません。 良い例 description: | Pythonコードのセキュリティレビューを実施。 OWASP Top 10に基づく脆弱性チェック、認証・認可の検証、入力バリデーション確認。 セキュリティチェック、脆弱性診断、コードのセキュリティ評価時に使用。 良いdescriptionのポイント: 具体的な動作 : 何をするスキルか明確に トリガーワード : どんな言葉で呼び出されるべきか 使用シーン : どんな状況で使うか 境界線 : 何に使わないか(オプション) Skillsの呼び出しの仕組み プログレッシブ・ディスクロージャー Skillsは段階的に情報を読み込む設計になっています: 1. 起動時 └─ 全スキルの name と description だけを読み込み 2. ユーザーリクエスト受信 └─ description を参照してマッチするスキルを判断 3. スキル選択時 └─ SKILL.md の本文を読み込み 4. 必要に応じて └─ scripts/ や references/ を読み込み この設計により、多数のスキルをインストールしても、実際に使うスキルの情報だけがコンテキストを消費します。 スクリプトの活用 Skillsの強力な機能の1つが、 Pythonスクリプトの実行 です。 指示だけでは不確実な処理(フォーマット、バリデーションなど)をスクリプトで確実に実行できます。 例:フォーマッタースキル --- name: python-formatter description: | Pythonコードをプロジェクト標準にフォーマット。 Black, isort, ruffを適用。Pythonファイルの整形時に使用。 version: 1.0.0 --- # Python Formatter ## Workflow ### Step 1: フォーマット実行 Run: `python .claude/skills/python-formatter/scripts/format.py <file>` ### Step 2: 結果確認 フォーマット結果を確認し、問題があれば報告。 # scripts/format.py import subprocess import sys def main(): file = sys.argv[1] subprocess.run(["black", file]) subprocess.run(["isort", file]) print(f" Formatted: {file}") if __name__ == "__main__": main() スクリプトのメリット 確実性 : LLMの揺らぎなく、決まった処理を実行 コンテキスト節約 : スクリプトの内容ではなく、出力だけがトークンを消費 再利用性 : 同じスクリプトを複数のスキルで共有可能 Skillsが有効なケース・有効でないケース  有効なケース 定型的なレビュー作業 : セキュリティチェック、コード品質チェック ドキュメント生成 : API仕様書、README、ADRなど フォーマット・バリデーション : スクリプトと組み合わせて確実に実行 プロジェクト固有のルール適用 : ブランドガイドライン、コーディング規約  有効でないケース 創造的なタスク : アイデア出し、自由な設計 対話的な作業 : フィードバックを受けながら進める作業 コンテキスト依存の判断 : プロジェクト全体を俯瞰した判断 単純な質問応答 : スキルを使うまでもないタスク ベストプラクティス 1. スキルはフォーカスを絞る 1つのスキルに複数の機能を詰め込まず、目的別に分割しましょう。 ❌ code-helper(何でもやる) ✅ security-review(セキュリティ特化) ✅ test-generator(テスト生成特化) ✅ api-design(API設計特化) 2. SKILL.mdは500行以下に 長すぎるスキルはコンテキストを圧迫します。詳細は別ファイルに分割し、SKILL.mdはメニューとして機能させましょう。 3. 具体例を含める Claudeが「成功とは何か」を理解できるよう、入出力の例を含めましょう。 4. 制限事項を明記する スキルができないことを明示すると、誤用を防げます。 セキュリティ上の注意 Skillsは強力な機能ですが、注意点もあります: 信頼できるソースのみ使用 : 自作またはAnthropicの公式スキルを推奨 APIキーをハードコードしない : 環境変数を使用 ダウンロードしたスキルは監査 : 実行前にスクリプトの内容を確認 まとめ Claude Code Skillsは、AIコーディングを「汎用アシスタント」から「プロジェクト専門家」に進化させる機能です。 ポイントをまとめると: descriptionが命 : 適切に書かないと呼び出されない 段階的読み込み : 多数のスキルを入れてもパフォーマンスに影響しにくい スクリプト活用 : 確実に実行したい処理はコード化 フォーカスを絞る : 1スキル1目的で設計 まずはシンプルなスキルから始めて、徐々に拡張していくのがおすすめです。 次の記事では、Web開発で使い回せる汎用スキル集を紹介します。 この記事はClaude Code公式ドキュメントおよび実際の検証に基づいて作成しています。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Claude Code Skillsの使い方と汎用テンプレート公開 first appeared on SIOS Tech Lab .
アバター
こんにちは、PS-SLの織田です。SIOS Tech Labアドベントカレンダー5日目になります。 今回のブログは資格取得に関するものになります。今年の7月に Azure Administrator Associate(AZ-104) に合格しました。この試験は、Azureの広範な知識と実践的な理解が求められるため、闇雲に学習を進めてもなかなか成果が出にくいものです。 私が実際に行った学習方法の中で特に効果的だった方法と、これから受験される方への具体的なアドバイスを、私の失敗談も交えながら、詳しくご紹介します。 最も合格に直結した学習リソース 私の学習において、最も合格に直結し、知識の定着に役立ったのはUdemyで提供されている高品質な予想問題集でした。学習を始めた当初は、「試験問題はAzureリソースのことをよく理解してから解いたほうが良いかな…」と考えていたのですが、むしろこの問題集を中心に学習を進めた方がよいと後になって気づきました。 本番さながらのシミュレーション : 予想問題集は、実際の試験と同じように、複数の選択肢、ドラッグアンドドロップ、ケーススタディなど、多様な問題形式で構成されています。時間を計って模擬試験として取り組むことで、 2時間の制限時間内に問題を解ききるペース配分 を身につけることができました。 出題傾向の把握と知識の定着 : 実際に本番と非常に似た、あるいは全く同じトピックの問題が出題されることが多々あります。これにより、試験で問われる核となる概念や、細かい設定項目についての理解が深まります。 正解の選択肢だけでなく、不正解の選択肢がなぜ間違っているのか を理解することで、知識をより確固たるものにすることができました。実際に本番では、練習問題とほぼ同じ問題が多数出題されました。練習問題をやりこむことで大きく加点を増やすことができ合格率を高めることができます。 本番環境を意識したMSLearn活用 AZ-104試験の最大の特徴は、試験中に公式ドキュメントであるMS Learnを参照することが許可されている点です。自分は高校や大学の試験のように「全てを暗記する」必要があると勘違いしていたのですが、実は「調べる力」も求められる試験でした。 MSLearnで「調べる力」を鍛える : 合格の鍵は、「どのトピックについて問われているか」を瞬時に判断し、「MS Learnのどのページを見れば確実な情報が得られるか」の当たりをつける能力です。最初のうちは欲しいページを探すのに時間がかかってしまいますが、繰り返し行っていくうちに素早く欲しいページを見つけられるようになります。 練習中からMS Learnを確認する習慣 : 予想問題集を解く際も、最初から「MS Learnを見ても良い」という本番ルールを適用し、常に「この問題はMS Learnのどのページを見れば解決できるか」という視点で検索する癖をつけましょう。 ドキュメント構造に慣れる : 練習を通じて、各Azureサービス(例:Virtual Machines、VNet、Storage Account)の概要ページ、料金ページ、具体的なデプロイ手順やトラブルシューティングに関するドキュメントが、MS Learnのどこに、どのようなキーワードで存在しているか、おおよその「あたり」を頭の中に作り上げておくことが、本番での貴重な時間短縮につながります。 Azure Storage アカウントの種類をまとめた表。このような同一サービスにおける種類・プランによる差異を比較できるページにあたりをつけておくと試験本番で重宝する。 私の失敗談:モチベーションの回復から推奨学習サイクルへ 実は、私の学習の初期段階では大きな失敗がありました。 最初は自分の実力を測ろうと、MS Learnを全く見ずに予想問題集に挑戦しました。結果は散々で、ほとんどの問題が分からず、スコアも非常に低く、 「こんなに難しいのか」とモチベーションが一気に低下 してしまいました。 しかし、合格した方からのアドバイスや冷静に試験の特性を考え直した結果、学習方法を根本的に変更しました。 推奨する効率的な学習サイクル 私が最も効果的だと思った学習サイクルは以下の通りです。 MS Learnを参照しながら練習問題を解く : 最初は正解率を気にせず、「どのドキュメントが使えるか」を探しながら解きます。問題を解くための手がかりを検索する能力を養うことに集中します。 間違った問題・自信のない問題の徹底的な深掘り(深掘り学習) : 単に正解の解説を読むだけでなく、間違えた理由や、偶然正解したものの自信がないトピックについては、徹底的に時間をかけて深く理解します。 「深掘り学習」の具体的なアプローチ 深掘りとは、単なる知識の丸暗記ではなく、その知識を多角的に理解し、本番で応用できる状態にすることです。 多角的な情報の整理 : 表や図の活用 : 例えば、ストレージアカウントの異なる冗長オプション(LRS, GRS, ZRS, GZRS)の特性や、VMの異なるサイズ(SKU)の機能や価格の違いなど、 比較が必要な情報を自分なりに表や図に整理 します。 実践的な比較 : 似た機能を持つAzureリソース(例:Azure FirewallとNetwork Security Group)について、それぞれの ユースケース、メリット・デメリット を対比して整理します。 公式ドキュメントとの紐づけ : 「この問題はMS Learnのどのドキュメントに該当する内容か」を再確認し、 いつでもそのページにすぐにたどり着けるように、キーワードや目次構造を脳内にインデックス化 します。 特に、PowerShellやAzure CLIのコマンド例が問われる問題については、MS Learnで実際のコマンドを確認し、なぜその引数が必要なのかを理解します。 実際に私が作成した冗長オプションをまとめた図。文字だけでは分かりずらい内容も図表にすることで視覚的に理解することができる。 まとめ 実は今回初めてテストセンターを利用して少し緊張していましたが、問題集をやりこんだおかげで、落ち着いていつも通り回答することができたと思います。練習問題をやりこんでおいてよかったです。 ただし、今回ご紹介した方法はあくまで一例ですので、参考程度に見てもらえればと思います。実際に学習を進める過程でご自身に合った学習方法で進めていくと良いかなという感じです。皆さんの学習が効率的に進むことを願っています! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post AZ-104 合格体験記:効果的な学習法と予想問題集の活用戦略 first appeared on SIOS Tech Lab .
アバター
はじめに こんにちは!サイオステクノロジーの吉永です。 この記事は「 SIOS社員が今年一年で学んだこと 」のアドベントカレンダー4日目の記事です。今年は生成AI活用事業やWEBアプリケーション開発に携わる中で、AIコーディングアシスタントとの協業について多くのことを学びました。今回は試行錯誤を重ねる中で、今年になって流行りだした「仕様駆動開発(SDD)」と実現するためのツールについて書こうと思います。 先日、OSC福岡2025で「もうAIに振り回されない!OpenSpecで実現する予測可能なAI開発」というテーマで登壇する機会もいただき、この一年の学びを整理することができました。本記事では、その内容をより詳しくお伝えしたいと思います。 さて、AIコーディングアシスタント(Claude Code、GitHub Copilot、Cursorなど)を使っていると、こんな経験はありませんか? 「ユーザー認証機能を追加して」と頼んだら、1000行のコードが生成された 「いや、JWTじゃなくてセッション認証で…」と訂正したら、また1000行のコードが生成された 「そもそもReactじゃなくてNext.jsで…」と再度訂正したら、さらに1000行のコード生成… この無限ループ地獄、実は「Vibeコーディング」と呼ばれる現象なんです。 Vibeコーディングとは何か 「Vibeコーディング」という言葉は、OpenAIの共同創業者であるAndrej Karpathyが2025年2月に初めて提唱した概念です。LLM(大規模言語モデル)の性能が飛躍的に向上したことで可能になった、全く新しい開発スタイルを指します。 There's a new kind of coding I call "vibe coding", where you fully give in to the vibes, embrace exponentials, and forget that the code even exists. It's possible because the LLMs (e.g. Cursor Composer w Sonnet) are getting too good. Also I just talk to Composer with SuperWhisper… — Andrej Karpathy (@karpathy) February 2, 2025 Vibeコーディングの特徴 Vibeコーディングは、従来のソフトウェア開発の常識を覆すような特徴を持っています。まず、 コードの存在を忘れて感覚的に開発する という点が挙げられます。開発者はコードの詳細を理解することなく、AIに自然言語で指示を出すだけで機能が実装されていきます。 エラーメッセージが表示されても、その意味を理解しようとはせず、 コメントなしでそのままコピペ してAIに投げます。AIが何らかの修正を提案してくれることを期待するわけです。 さらに驚くべきことに、 コードが開発者の理解を超えて成長 していきます。気づいたら数千行のコードベースになっていて、その全貌を誰も把握していないという状況が生まれます。音声入力でAIに指示を出すことも一般的で、散歩しながらコーディングすることも可能です。 バグに遭遇した場合は、修正できなければ回避策で対処するか、 ランダムな変更を加えてバグが消えるまで試す というアプローチが取られます。これは従来のデバッグとは全く異なる手法です。 一見すると非常に効率的で革新的に見えますが、実はこのアプローチには深刻な問題が潜んでいます。 根本的な4つの問題 Vibeコーディングの背後には、以下の4つの根本的な問題が存在します。 曖昧な要求仕様 最も大きな問題は、「何を作るか」が明確でないことです。開発者が曖昧な指示をすると、AIは自身の学習データに基づいて推測で補完します。例えば「ユーザー認証を追加して」と言った場合、AIはJWT認証、セッション認証、OAuth、Basic認証など、様々な選択肢の中から独自に判断して実装を進めます。 結果として、開発者が意図していた認証方式とは全く異なる実装が生成されることになります。これを修正するために再度プロンプトを投げると、また別の実装が生成される…という無限ループに陥るのです。 コンテキストの欠如 プロジェクトには必ず技術スタック、コーディング規約、アーキテクチャパターンといった プロジェクト固有のコンテキスト が存在します。しかし、これらの情報がAIに伝わっていないと、既存のコードベースに適合しないコードが生成されてしまいます。 例えば、プロジェクトがNext.js 15のApp Routerを使っているのに、AIがPages Routerで実装してしまう。データベースアクセスにPrismaを使っているのに、生SQLで書かれてしまう。このような不整合が頻発します。 非決定的な出力 LLMの性質上、同じプロンプトでも毎回違う結果が返ってきます。これは 再現性の欠如 を意味します。昨日うまくいった方法が今日は通用しない。同僚が成功した方法を自分が試しても同じ結果にならない。このような状況では、チーム開発が非常に困難になります。 知識の散逸 AIとの対話の中で重要な決定事項が決まっていきます。「このAPIはRESTfulに設計する」「認証トークンはHTTP-onlyクッキーに保存する」「エラーハンドリングは専用のミドルウェアで行う」など、プロジェクトの重要な方針が決まっていくわけです。 しかし、これらの 決定事項はチャット履歴に埋もれてしまい 、後から見返すことができません。新しいセッションを始めたり、別の開発者が作業を引き継いだりすると、同じ議論を最初からやり直すことになります。 これらの問題を解決するため、コミュニティでは様々なアプローチが試みられてきました。 Vibeコーディングの問題を解決するため、最初に登場したのが CLAUDE.md というアプローチです。 CLAUDE.mdの登場 CLAUDE.mdは、プロジェクトのルートディレクトリに配置する AIへの指示書 です。Anthropic社のClaude Codeに特化しており、プロジェクトのガイドライン、ベストプラクティス、制約事項などを記述します。 従来のアプローチ:CLAUDE.md/AGENTS.md これにより、先ほど述べた「コンテキストの欠如」という問題を解決しようとしました。AIがプロジェクトの技術スタック、コーディング規約、アーキテクチャパターンを理解できるようになるわけです。 # プロジェクト概要 ECサイトのバックエンド開発 ## 技術スタック - Node.js + TypeScript - Express.js、PostgreSQL、Jest ## コーディング規約 - 関数は単一責任の原則に従う - エラーハンドリングは必須 - テストファーストで実装 ## 実装時の注意 1. TypeScriptの型定義を含める 2. APIはRESTfulに設計 3. 認証はJWT Bearer tokenを使用 CLAUDE.mdは2025年6月頃から段階的に進化してきました。 CLAUDE.mdの進化 第1段階(2025年6月頃) では、単なる チートシート として使われていました。プロジェクトの基本情報を提供し、よく使うコマンドをリスト化する程度の内容でした。この段階では、開発者がマニュアルを見る手間を省く程度の効果しかありませんでした。 第2段階(2025年7月〜9月) になると、 AIの制約を定義 するツールへと進化しました。詳細なスタイルガイドを記述し、ワークフローを自動化する指示を含めるようになりました。さらに、過去の失敗から学習するため、「やってはいけないこと」のリストも追加されました。 モノレポ(複数のプロジェクトを1つのリポジトリで管理する構成)に対応するため、階層的な設定管理も可能になりました。ルートのCLAUDE.mdで全体的なルールを定義し、各サブプロジェクトのCLAUDE.mdで個別のルールを上書きできるようになったのです。 AGENTS.mdの登場 2025年8月19日、OpenAIが AGENTS.md をオープンフォーマットとして公開しました。これは、Anthropic社独自のCLAUDE.mdをより汎用的にしたものです。 AGENTS.mdの最大の特徴は、 複数のAIツール間で共有される共通指示 として機能することです。Claude Code、GitHub Copilot、Cursor、Windsurf、Aiderなど、様々なAIコーディングアシスタントで同じ指示書を使い回せます。 また、 推奨言語は英語 です。これには明確な理由があります。AIモデルの学習データは英語が圧倒的に多く、技術用語も英語の方が曖昧性が少ないためです。国際的なチームで開発する場合も、英語で書かれていれば誰でも理解できます。 AGENTS.mdには、以下のような内容が含まれます: 実装ガイドライン として、コード規約(命名規則、ファイル構成、型定義)、エラーハンドリングパターン、セキュリティチェックリスト、認証実装パターンなどを記述します。 ワークフロー指示 として、新機能開発プロセス(要件確認→実装→検証→コミット)、バグ修正プロセス、コードレビュー基準などを定義します。 これにより、AIは単にコードを生成するだけでなく、プロジェクトのワークフローに沿った作業を進められるようになりました。 CLAUDE.md/AGENTS.mdの限界 しかし、CLAUDE.md/AGENTS.mdにも限界があることが分かってきました。特に、プロジェクトが成長するにつれて以下の問題が顕在化してきたのです。 仕様の管理が困難 プロジェクト全体の説明が1つのファイルに含まれているため、様々な問題が発生します。 まず、 すべての機能の仕様が混在 してしまいます。認証機能、決済機能、通知機能、管理画面…といった個別の機能の仕様が、すべて1つのファイルに書かれることになります。ファイルが肥大化し、数千行になることも珍しくありません。 次に、 過去の決定事項がどこかに埋もれて しまいます。「3ヶ月前に決めた認証方式の詳細はどこに書いてあったっけ?」と探しても、膨大なファイルの中から該当箇所を見つけるのは困難です。 また、 現在作業中の内容が見つけにくい という問題もあります。複数の機能を並行して開発している場合、どれが完了していて、どれが進行中で、どれが未着手なのか、ファイルを読むだけでは判断できません。 さらに深刻なのは、 途中参加メンバーが全体像を把握することが困難 という点です。新しく参画したエンジニアが数千行のCLAUDE.md/AGENTS.mdを読んでも、プロジェクトの歴史的経緯や現在の状態を理解するのは非常に難しいのです。 変更の追跡が不可能 CLAUDE.md/AGENTS.mdはGitで管理されているため、理論上は変更履歴を追跡できます。しかし実際には、 どの機能がいつ追加されたかを把握するのは困難 です。 ファイル全体の差分を見ても、「500行目に3行追加、800行目に5行修正」といった情報しか得られません。それが認証機能の変更なのか、決済機能の追加なのか、コーディング規約の更新なのか、差分だけでは判断できないのです。 仕様変更の履歴が残らない ことも問題です。「なぜ認証方式をJWTからセッション認証に変更したのか?」という意思決定の背景が記録されていないため、同じ議論が何度も繰り返されることになります。 複数人で作業している場合、この問題はさらに深刻です。メンバーAが認証機能の仕様を更新し、同時にメンバーBが決済機能の仕様を追加すると、Gitのコンフリクトが発生します。1つのファイルに全てが集約されているため、 並行作業が非常に困難 なのです。 さらに、 セッションが異なると情報が共有されない という問題もあります。Claude Codeで月曜日に作業した内容が、火曜日の新しいセッションでは引き継がれません。CLAUDE.mdに書かれていない暗黙的な決定事項は、毎回失われてしまうのです。 スケーラビリティの欠如 最も深刻なのは、 プロジェクトが大きくなると管理不能になる ことです。 小規模なプロジェクト(1〜2人、数ヶ月の開発期間)であれば、CLAUDE.md/AGENTS.mdは十分機能します。しかし、10人以上のチーム、1年以上の開発期間となると、話は別です。 特に、既存機能の変更(1→N)が困難です。新しい機能を0から作る場合(0→1)は、CLAUDE.md/AGENTS.mdに新しいセクションを追加すればよいだけです。しかし、既存の機能を変更する場合(1→N)、ファイル内の該当箇所を見つけ、整合性を保ちながら更新する必要があります。 大規模プロジェクトでは、各フォルダにCLAUDE.md/AGENTS.mdが点在することもあります。frontend/CLAUDE.md、backend/CLAUDE.md、infra/CLAUDE.mdといった具合です。これらのファイル間で矛盾が生じると、AIはどちらを優先すべきか判断できず、混乱してしまいます。 結果として、 全体像の把握が困難 になります。プロジェクトの現在の状態を理解するには、複数のCLAUDE.md/AGENTS.mdをすべて読み、Gitの履歴を追跡し、さらにコードベースを確認する必要があります。 これらの限界を克服するため、新しいアプローチが求められました。それが 仕様駆動開発(SDD) です。 仕様駆動開発(SDD)の台頭 2025年に入って、 仕様駆動開発(Spec-Driven Development、SDD) という新しいアプローチが急速に注目を集めるようになりました。 SDDの本質 SDDの本質は、一言で表すと以下のようになります: 「コードを書く前に、何を作るかをAIと合意する」 これは当たり前のように聞こえるかもしれません。しかし、Vibeコーディングの時代には、この「当たり前」が忘れ去られていたのです。 従来のソフトウェア開発では、要件定義→設計→実装という順序が基本でした。しかし、AIコーディングアシスタントの登場により、「とりあえずAIにコードを書かせてみて、動かなかったら修正する」というアプローチが一般化しました。 SDDは、AIコーディング時代においても、 設計の重要性 を再認識させてくれるアプローチなのです。 SDDのキーコンセプト SDDには、4つのキーコンセプトがあります。 明確な仕様定義 は、曖昧さを排除することを目指します。「ユーザー認証を追加して」ではなく、「Google OAuthを使った認証を追加し、セッションは24時間有効とし、ログアウト機能も提供する」といった具体的な仕様を定義します。 人間とAIの共通理解 は、同じ認識を持つことを重視します。AIが生成するコードが、開発者の意図と完全に一致するよう、事前に仕様をすり合わせます。これにより、「期待と違う」という問題を大幅に減らせます。 予測可能な実装 は、実装前に結果が見えることを意味します。詳細な仕様があれば、実装後のコードがどのようになるか、事前に予測できます。これにより、手戻りを最小限に抑えられます。 追跡可能な変更 は、いつ、何が変わったかを明確にします。仕様の変更履歴を残すことで、「なぜこうなっているのか」という疑問に答えられるようになります。 従来フローとSDDフローの違い この違いを図で表すと、非常に明確です。 従来の Vibeコーディングフロー は、以下のような循環構造になっています: アイデアをプロンプトに変換し、AIがコードを生成します。生成されたコードをデバッグし、問題があれば修正します。しかし、修正してもまた別の問題が発生し、フラストレーションが溜まっていきます。結局、最初に戻って別のアプローチを試す…という無限ループに陥るのです。 一方、 SDDの開発フロー は、直線的で明確です: アイデアを仕様という形で文書化します。その仕様を人間がレビューし、AIと合意します。合意が得られてから初めて実装に移ります。実装が完了したら、仕様をアーカイブして知識として蓄積します。各ステップが明確で、後戻りが最小限に抑えられているのが特徴です。 SDDがもたらす4つの価値 SDDは、開発プロセスに以下の4つの価値をもたらします。 予測可能性 により、実装前に結果が予測できます。詳細な仕様があれば、「この機能を実装すると、データベーススキーマはこうなり、APIエンドポイントはこれだけ追加され、フロントエンドコンポーネントはこう変更される」ということが事前に分かります。これにより、予期しない副作用を防げます。 監査可能性 により、すべての変更が追跡可能です。仕様の変更履歴を見れば、「いつ、誰が、なぜ、この変更を行ったか」が明確に分かります。コンプライアンスやセキュリティ監査においても、この追跡可能性は非常に重要です。 再利用性 により、仕様が知識として蓄積されます。過去のプロジェクトで作成した認証機能の仕様を、新しいプロジェクトで再利用できます。同じ問題を何度も解決する必要がなくなるのです。 チーム協業 により、異なるAIツールでも同じ仕様を共有できます。メンバーAがClaude Codeを使い、メンバーBがCursorを使っていても、同じ仕様を参照していれば、一貫性のあるコードが生成されます。 現在の主要なSDDツール(2025年11月時点) SDDを実現するツールは、2025年に次々と登場しました: Kiro  (AWS) – https://kiro.dev Spec Kit  (GitHub) – https://github.com/github/spec-kit OpenSpec  (Fission AI) – https://github.com/Fission-AI/OpenSpec BMad Method  (BMad Code) – https://github.com/bmad-code-org/BMAD-METHOD cc-sdd  (国産OSSツール) – https://github.com/gotalab/cc-sdd それぞれのツールには特徴がありますが、今回はOpenSpecを中心にご紹介します。 OpenSpecとは OpenSpecは、Fission AIが開発した仕様駆動開発を実現する軽量なワークフロー管理ツールです。 OpenSpecが解決する問題 OpenSpecは、先ほど述べたCLAUDE.md/AGENTS.mdの限界を、直接的に解決することを目指して設計されています。 既存プロジェクト向けに最適化 されているのが、OpenSpecの最大の特徴です。新規プロジェクトを0から立ち上げる場合ではなく、すでに動いているプロジェクトに後から導入できるよう設計されています。既存のコードベースに影響を与えることなく、段階的に導入できます。 複数のAIツールに対応 しているのも重要なポイントです。Claude Code、Cursor、GitHub Copilot、Aiderなど、様々なAIコーディングアシスタントで使えます。チームメンバーがそれぞれ異なるツールを使っていても、同じ仕様を共有できるのです。 軽量な構造 により、学習コストが低いことも魅力です。複雑な設定ファイルやビルドツールは不要で、基本的にはMarkdownファイルを編集するだけです。既存のドキュメント作成スキルがあれば、すぐに使い始められます。 変更管理の明確化 は、OpenSpecの核心的な機能です。Gitのpull requestのように、仕様の差分を明確に管理できます。「何が追加され、何が変更され、何が削除されたか」が一目で分かります。 OpenSpecワークフロー OpenSpecは、以下の4つのステップで動作します。 Proposal(提案)では、変更内容を提案します。「二要素認証を追加したい」「検索機能にフィルタを追加したい」といった変更を、構造化された形で提案します。この段階では、まだコードは生成されません。 Review(レビュー)では、提案された仕様を確認・調整します。人間が仕様を読み、不明点があればAIと対話しながら詳細化していきます。この段階で、実装の方向性が固まります。 Apply(適用)では、合意された仕様に基づいて実装を実行します。AIが仕様を読み取り、それに従ってコードを生成します。仕様が明確なので、AIの出力も予測可能です。 Archive(アーカイブ)では、完了した変更を知識として蓄積します。提案時に作成した変更差分を、マスター仕様に統合します。これにより、プロジェクトの仕様が常に最新の状態に保たれます。 OpenSpecの核となる概念:2つのフォルダ OpenSpecの構造は、驚くほどシンプルです。基本的に、2つのフォルダで構成されています。 AGENTS.md openspec/ ├── specs/          # 現在の仕様 │   └── auth/ │       └── spec.md # 認証機能の仕様 │ └── changes/        # 提案中の変更     └── add-profile-filters/     |   ├── proposal.md  # 変更内容     |   ├── tasks.md     # タスクリスト     |   ├── design.md    # 技術仕様     |   └── specs/     |       └── auth/     |           └── spec.md # 仕様の差分     └── add-frontend-ui/ openspec/specs/ フォルダには、現在の仕様を管理します。これは、プロジェクトの「現在の状態」を表します。認証機能、決済機能、検索機能など、各機能の仕様が独立したファイルとして管理されます。 openspec/changes フォルダには、提案中の変更を管理します。これは、プロジェクトの「未来の状態」を表します。各変更提案は独立したディレクトリとして管理され、その中に提案内容、タスクリスト、技術仕様、仕様の差分などが含まれます。 この構造により、 CLAUDE.md/AGENTS.md の「すべてが1つのファイルに混在する」という問題が解決されます。また、複数の変更を並行して進めることも容易になります。 変更差分の概念 OpenSpecの最も強力な機能の1つが、Gitのpull requestと同様の変更差分管理です。 # プロフィール仕様の変更差分 ## ADDED Requirements ### 要件: ロールフィルター システムはユーザーロールによるフィルタリングを提供しなければならない ## MODIFIED Requirements ### 要件: 検索レスポンス(更新版) 検索結果にはフィルター適用状態を含めなければならない ## REMOVED Requirements ### 要件: 全件表示 (廃止:パフォーマンスの問題により) この差分形式により、レビュー時に何が変わるのかが一目で分かります。 ADDED セクションには、新しく追加される要件が記載されます。この例では、「ロールフィルター」という新機能が追加されることが分かります。 MODIFIED セクションには、既存の要件の変更が記載されます。「検索レスポンス」という既存の要件が更新され、フィルター適用状態を含むようになることが分かります。 REMOVED セクションには、廃止される要件が記載されます。「全件表示」機能がパフォーマンスの問題により廃止されることが分かります。 この差分形式は、Gitのdiffやプルリクエストに慣れているエンジニアにとって、非常に理解しやすいものです。コードレビューと同じように、仕様もレビューできるのです。 OpenSpecの実際の使い方 実際のシナリオを使って、OpenSpecの使い方を詳しく見ていきましょう。 シナリオ:二要素認証(2FA)を追加 既存の認証システムに2FA(二要素認証)を追加する場合を考えます。現在はメールアドレスとパスワードによる認証のみですが、セキュリティ向上のため、SMSまたは認証アプリによる2FAを追加したいとします。 Step 1: 変更提案の作成 まず、変更提案を作成します。コマンドラインから直接実行することも、AIアシスタントに自然言語で依頼することもできます。 # コマンドライン、またはAIアシスタントに依頼 /openspec:proposal 二要素認証を追加 または、より自然な言葉で: 開発者: 「プロフィール検索にロールとチームでのフィルター機能を 追加するOpenSpec変更提案を作成して」 AI: 「OpenSpec変更提案を作成します...」 *openspec/changes/add-profile-filters/を生成* このコマンドを実行すると、AIが自動的に以下のファイル構造を生成します: openspec/changes/add-2fa/ ├── proposal.md # 変更の意図と背景 ├── tasks.md # 実装タスクリスト ├── design.md # 技術仕様 └── specs/auth/ └── spec.md # 2FAの仕様(差分) proposal.md には、なぜこの変更が必要なのか、どのような価値を提供するのかといった背景情報が記載されます。「セキュリティ向上のため、2FAを導入する。これにより、不正アクセスのリスクを大幅に低減できる」といった内容です。 tasks.md には、実装に必要なタスクが列挙されます。「データベーススキーマに2FA用のテーブルを追加」「SMS送信機能を実装」「認証アプリとの連携機能を実装」「フロントエンドに2FA設定画面を追加」といった具体的なタスクです。 design.md には、技術的な設計が記載されます。「2FAのコードは6桁の数字とし、有効期限は5分間」「SMS送信にはTwilio APIを使用」「認証アプリとの連携にはTOTPプロトコルを使用」といった技術的な決定事項です。 specs/auth/spec.md には、認証機能の仕様の差分が記載されます。これが最も重要なファイルで、既存の認証仕様に対する変更点が明確に示されます。 Step 2: 仕様のレビューと調整 生成された仕様を確認し、必要に応じて調整していきます。この段階では、AIと対話しながら仕様を詳細化していきます。 開発者: 「ロールとチームフィルターの受け入れ条件を追加して」 AI: 「仕様差分を更新します…」     specs/profile/spec.mdとtasks.mdを編集 例えば、「2FAのバックアップコードはどうするか?」「2FAの設定は任意か必須か?」「既存ユーザーへの移行はどうするか?」といった疑問点を、この段階でAIと議論します。 AIが提案する仕様に納得できない場合は、何度でも修正を依頼できます。「バックアップコードは10個生成し、1回使用したら無効にする」「既存ユーザーは次回ログイン時に2FA設定を促すが、強制はしない」といった具体的な要件を追加していきます。 この段階では、まだコードは一切生成されていません。 仕様を固めることに集中します。コードを書く前に設計を固めるという、ソフトウェア開発の基本原則に立ち返っているわけです。 Step 3: 実装 仕様に合意したら、いよいよ実装フェーズに移ります。 # コマンドライン、またはAIアシスタントに依頼 /openspec:apply add-profile-filters または、自然言語で: 開発者: 「仕様が良さそうです。実装しましょう」 AI: 「タスクを順番に実装します...」 Task 1.1 ✓ データベーススキーマ更新 Task 1.2 ✓ APIエンドポイント追加 Task 2.1 ✓ フロントエンドコンポーネント作成 AIは、tasks.mdに記載されたタスクを順番に実行していきます。各タスクが完了するたびに、進捗が表示されます。 仕様が明確なので、AIの出力も予測可能です。「データベーススキーマ更新」タスクでは、予想通り user_2fa テーブルが追加されます。「APIエンドポイント追加」タスクでは、 POST /api/auth/2fa/enable 、 POST /api/auth/2fa/verify といったエンドポイントが実装されます。 もし問題が発生した場合でも、どのタスクで問題が起きたかが明確なので、デバッグが容易です。タスクは小さな単位に分割されているため、問題の切り分けがしやすいのです。 Step 4: アーカイブと知識の蓄積 実装が完了し、テストも通ったら、変更をアーカイブします。 # コマンドライン、またはAIアシスタントに依頼 /openspec:archive add-profile-filters または、自然言語で: このコマンドを実行すると、以下のことが起こります: 開発者: 「変更をアーカイブして」 AI: 「変更をアーカイブします...」 *openspec archive add-profile-filters --yes* ✓ 仕様が更新されました openspec/changes/add-2fa/specs/auth/spec.md (差分)が、 openspec/specs/auth/spec.md (マスター仕様)に統合されます openspec/changes/add-2fa/ ディレクトリが削除されます Git履歴に、この変更が記録されます 結果として、openspec/specs/フォルダには常に最新の仕様が保たれ、openspec/changes/`フォルダには進行中の変更のみが残るという、クリーンな状態が維持されます。 CLAUDE.mdのみの場合との比較 ここで、従来のCLAUDE.mdのみを使った場合と、OpenSpecを使った場合を比較してみましょう。 CLAUDE.mdのみの場合の作業フロー: CLAUDE.mdをエディタで開く どこに2FAの仕様を書くべきか迷う(認証セクション?セキュリティセクション?新しいセクション?) 適当な場所に仕様を追記する AIにプロンプト:「2FAを追加して」 AIが大量のコードを生成する(1000行以上になることも) 生成されたコードをレビューしようとするが、何が変更されたのか分からない 既存の認証ロジックへの影響範囲が不明 他の開発者がCLAUDE.mdを更新していて、Gitコンフリクトが発生 コンフリクトを解決するが、自分の変更と他の人の変更が混ざって分かりにくい 結果: × 仕様がCLAUDE.md内で埋もれる(後から見つけるのが困難) × 変更履歴が残らない(なぜこの仕様になったかが不明) × チーム間での共有が困難(誰が何を変更したか分からない) OpenSpecを使用した場合の作業フロー: /openspec:proposal 二要素認証を追加 とコマンド実行 構造化されたファイル群が自動生成される proposal.md、tasks.md、design.md、spec差分を順番にレビュー 不明点があればAIと対話しながら詳細化 仕様に合意したら /openspec:apply で実装開始 タスクごとに進捗を確認できる 各タスクの成果物をその場でレビュー 問題があれば該当タスクだけを修正 完了後に /openspec:archive で知識として蓄積 他の開発者は別の変更提案で並行作業可能(コンフリクトなし) 結果: ✓ 変更内容が明確(dedicated directoryで管理) ✓ 影響範囲が把握できる(差分形式で表示) ✓ チーム全体で知識を共有(アーカイブで蓄積) ✓ 並行作業が可能(changes/以下で分離) 既存のAGENTS.md/CLAUDE.mdは不要? ここで疑問が生じます。「OpenSpecがあれば、AGENTS.md/CLAUDE.mdは不要なのか?」 答えは「 いいえ、併用が推奨されています 」です。 AGENTS.md/CLAUDE.mdとOpenSpecは役割が異なります。 AGENTS.md/CLAUDE.m dは、 全体的な指示を記述 します。プロジェクトのコーディング規約(「変数名はcamelCaseで書く」「ファイル名はkebab-caseで書く」など)、プロジェクト全体のアーキテクチャ(「MVCパターンを採用」「依存性注入を使う」など)、共通のワークフロー(「コミット前に必ずlintとtestを実行」など)といった、プロジェクト横断的なルールを定義します。 OpenSpec は、 個別機能の仕様を管理 します。認証機能の詳細な仕様、決済機能のAPI設計、検索機能のアルゴリズムなど、機能ごとの具体的な仕様を管理します。 両者は補完関係にあります。AGENTS.md/CLAUDE.mdが「プロジェクトの憲法」だとすれば、OpenSpecは「個別の法律」のようなものです。 OpenSpecは、AGENTS.md/CLAUDE.mdと統合するための特別なブロックを提供しています: <!-- OPENSPEC:START --> # OpenSpec 操作手順 この手順は、本プロジェクトで活動するAIアシスタント向けです。 以下のリクエスト時には常に `@/openspec/AGENTS.md` を開いてください: - 計画や提案に関する言及がある場合(proposal、spec、change、plan などの単語を含む) - 新機能の導入、互換性のない変更、アーキテクチャ変更、大規模なパフォーマンス/セキュリティ作業に関するもの - 曖昧な内容で、コーディング前に正式な仕様書が必要な場合 `@/openspec/AGENTS.md` で以下の内容を学習してください: - 変更提案の作成と適用方法 - 仕様書のフォーマットと規約 - プロジェクト構造とガイドライン この管理ブロックを維持し、「openspec update」で手順を更新できるようにしてください。 <!-- OPENSPEC:END --> このブロックを AGENTS.md に追加することで、AIアシスタントがOpenSpecの使い方を自動的に学習します。ユーザーが「新機能を追加したい」と言えば、AIは自動的にOpenSpecの変更提案を作成するようになります。上記のブロックは OpenSpec init 実行時に自動的に CLAUDE.md に追加されます。 他ツールとの比較 ここで、主要なSDDツールを比較してみましょう。OpenSpec以外にも、優れたSDDツールがいくつか存在します。 Kiro(AWS) Kiroは、AWSが開発したSDDツールです。 大規模プロジェクト向けに設計 されており、プロジェクトの方向性と個別機能の仕様を明確に分離する 2層構造 が特徴です。 .kiro/ ├── steering/          # プロジェクト方向性(変更頻度:低) │   ├── product.md     # プロダクトのビジョン、目標、ターゲットユーザー、主要機能 │   ├── tech.md        # 技術スタック、アーキテクチャ方針 │   └── structure.md   # ディレクトリ構造、命名規則 └── specs/             # 機能仕様(変更頻度:高)     └── add-2fa/         ├── requirements.md  # 機能要件         ├── design.md        # 技術設計         └── tasks.md         # 実装タスク プロジェクト構造: steering/ フォルダには、プロジェクト全体の方向性を定義します。これは 変更頻度が低い情報 です。 product.md には、プロダクトのビジョン、目標、ターゲットユーザー、主要機能といった、プロジェクトの根幹を成す情報が記載されます。例えば、「このアプリケーションは、中小企業の経理担当者をターゲットとした経費精算システムです。主要機能は、経費の申請・承認・精算です」といった内容です。 tech.md には、技術スタック、アーキテクチャ方針、使用するライブラリなどが記載されます。「Next.js 15 + NestJS + PostgreSQLを使用」「マイクロサービスアーキテクチャを採用」「認証にはAuth0を使用」といった技術的な決定事項です。 structure.md には、ディレクトリ構造、命名規則、モジュール間の依存関係などが記載されます。「フロントエンドは /frontend 、バックエンドは /backend に配置」「コンポーネント名はPascalCaseで書く」といった構造的なルールです。 一方、 specs/ フォルダには、個別機能の詳細仕様を定義します。これは 変更頻度が高い情報 です。 各機能ごとにディレクトリを作成し、その中に requirements.md (機能要件)、 design.md (技術設計)、 tasks.md (実装タスク)を配置します。 Kiroの2層構造の利点: この2層構造により、プロジェクトの憲法( steering/ )と個別の法律( specs/ )が明確に分離されます。 steering/ を変更するのは慎重に行うべきです。なぜなら、すべての機能に影響するからです。一方、 specs/ は頻繁に変更されます。新機能を追加するたび、既存機能を修正するたびに更新されます。 この分離により、チーム間の役割分担も明確になります。プロダクトマネージャーやアーキテクトは steering/ を管理し、個別の開発者は specs/ を管理する、といった分業が可能です。 大規模プロジェクト(数十人のチーム、数年にわたる開発)では、この構造が非常に有効です。 Spec Kit(GitHub) Spec Kitは、GitHubが開発したSDDツールです。 新規プロジェクトを0から立ち上げる際に最適化 されており、プロジェクトの立ち上げから運用まで、すべてのフェーズをカバーする重厚なドキュメント構成が特徴です。 プロジェクト構造: specs/001-todo-app-git-oauth/ ├── spec.md              # 機能仕様書 ├── checklists/ │   └── requirements.md  # 品質チェックリスト ├── plan.md              # 実装計画(技術選定) ├── research.md          # Phase 0: 技術調査 ├── data-model.md        # Phase 1: データモデル ├── contract/ │   └── openapi.yaml     # Phase 1: API制約 ├── tasks.md             # Phase 2: 実装タスク └── quickstart.md        # 開発者ガイド Spec Kitの特徴は、 4つのフェーズ に分かれた開発プロセスです。 Phase 0: 仕様作成 Phase 0: 仕様作成では、何を作るかを定義します。 spec.mdには、機能の概要、ユーザーストーリー、受け入れ基準などが記載されます。「エンジニアとして、Google OAuthでログインできるようにしたい。ログインに成功したら、ダッシュボードにリダイレクトされる」といった内容です。 research.md には、技術調査の結果が記載されます。「認証ライブラリとしてNextAuth.jsとAuth0を比較した結果、NextAuth.jsを採用する。理由は、Next.jsとの統合が容易であり、無料枠が充実しているため」といった調査レポートです。 Phase 1: 設計 Phase 1: 設計では、どう作るかを設計します。 plan.md には、実装計画が記載されます。技術選定の詳細な理由、アーキテクチャ図、開発スケジュール、リスク管理などが含まれます。 data-model.md には、データモデルが記載されます。「Userテーブルには、id (UUID)、email (string)、name (string)、createdAt (timestamp)を含む」といった具体的なスキーマ定義です。 contract/openapi.yaml には、APIの仕様がOpenAPI形式で定義されます。これにより、型安全性が確保され、APIドキュメントも自動生成できます。 Phase 2: 実装 Phase 2: 実装では、具体的な実装ステップを実行します。 tasks.md には、実装タスクが列挙されます。「プロジェクト初期化」「データベース設定」「認証エンドポイント実装」「ログインUI作成」といった具体的なタスクです。 Phase 3: レビュー Phase 3: レビューでは、実装内容の動作確認を行います。 quickstart.md には、開発者ガイドが記載されます。環境構築手順、開発サーバー起動方法、テスト実行方法、デプロイ手順などが含まれます。新メンバーが参画したとき、このquickstart.mdを読めばすぐに開発を始められるようになっています。 さらに、 checklists/requirements.md には、品質チェックリストが含まれます。機能要件、非機能要件、テストカバレッジ、ドキュメント、コード品質など、各項目について確認すべき事項がリスト化されています。 Spec Kitの強み: Spec Kitは、 新規プロジェクトを0から立ち上げる際の完全なガイド として機能します。何をどの順番で行えばよいか、何を確認すべきかが明確なので、経験の浅いチームでも品質の高いプロジェクトを立ち上げられます。 また、OpenAPI連携により型安全性を確保できるのも大きな利点です。APIの仕様が変更されたら、自動的に型定義も更新され、フロントエンドとバックエンドの不整合を防げます。 GitHub Copilotとの統合も考慮されており、GitHub上のプロジェクトで特に威力を発揮します。 3ツールの比較表 3つのツールを表で比較すると、以下のようになります: 特徴 OpenSpec Spec Kit Kiro 対象 既存PJ (1→N) 新規PJ (0→1) 全プロジェクト 構造 2フォルダ (specs + changes) 4フェーズファイル 2層構造 (steering + specs) 主要ファイル proposal.md tasks.md spec 差分 spec.md + research.md plan.md + data-model.md tasks.md quickstart.md product.md tech.md structure.md requirements.md design.md tasks.md 変更管理 差分 + アーカイブ Git履歴 Git履歴 価格 無料(AIツール利用料のみ) 無料(AIツール利用料のみ) 有料(毎月 無料枠あり) どれを選ぶべきか それぞれのツールには明確な使い分けがあります。 OpenSpec は、 既存プロジェクトに導入したい場合に最適 です。すでに動いているプロジェクトに後から導入でき、学習コストが低く、複数の変更を並行して進めやすいのが特徴です。 「今のプロジェクトにSDDを導入したいが、大きな変更は避けたい」「チームメンバーが異なるAIツールを使っている」「複数の機能を同時並行で開発している」といった状況では、OpenSpecが適しています。 Spec Kit は、 新規プロジェクトを立ち上げる場合に最適 です。0から丁寧にガイドしてくれ、ドキュメントが重厚で、品質チェックリストも完備されているのが特徴です。 「新しいプロジェクトをこれから始める」「チームメンバーに経験の浅い人が多い」「品質を重視したい」「GitHub Copilotを使っている」といった状況では、Spec Kitが適しています。 Kiro は、 大規模で長期的なプロジェクトでしっかりした構造が必要な場合に最適 です。steeringとspecsの2層構造が強力で、プロジェクトの方向性と個別機能を明確に分離できるのが特徴です。 「数十人規模のチームで開発している」「数年にわたるプロジェクト」「プロダクトマネージャーと開発者の役割分担を明確にしたい」「予算がある(有料ツールを導入できる)」といった状況では、Kiroが適しています。 AIコーディングの進化 AIコーディングは、ここ数年で劇的に進化してきました。 第1世代 : コード補完の時代(2021年頃〜)では、GitHub Copilot、TabNineなどのツールが登場しました。これらは、コードの一部を書くと、次の行を予測して補完してくれるというものでした。開発者の生産性は向上しましたが、あくまで「補完」に過ぎず、開発者が設計し、コードを書くという基本は変わりませんでした。 第2世代 : 対話型コード生成の時代(2023年頃〜)では、ChatGPT、Claude、Cursorなどが登場しました。自然言語で「ユーザー認証機能を作って」と指示すると、完全なコードが生成されるようになりました。これは革命的でしたが、同時にVibeコーディングという問題も生み出しました。 第3世代 : 仕様駆動開発の時代(2025年〜)では、OpenSpec、Kiro、Spec Kitなどが登場しました。コードを書く前に仕様を定義し、AIと合意するというアプローチです。これにより、予測可能で、監査可能で、再利用可能な開発が実現されました。 開発者の役割の変化 仕様駆動開発の登場により、開発者の役割も変化しています。 第2世代のAIコーディングでは、開発者は「 AIのサポートでコードを書く 」という役割でした。AIが生成したコードをレビューし、修正し、統合するという作業が中心でした。 第3世代のAIコーディングでは、開発者は「 仕様を設計し、AIを操縦する 」という役割に変化しています。コードを書く作業の多くはAIに任せ、開発者は「何を作るべきか」を明確に定義することに集中します。 ただし、以下の点は変わりません: コードを読む能力、理解する能力は依然として重要 です。AIが生成したコードが正しいかどうかを判断するには、コードを読み解く力が必要です。 コードを書く作業はAIに任せていく のが今後のトレンドです。単純なCRUD操作、ボイラープレートコード、テストコードなどは、AIに任せることで効率化できます。 そして、 「何を作るべきか」を明確に定義する能力がより重要 になっていきます。曖昧な指示ではなく、具体的で明確な仕様を書ける能力が、これからのエンジニアに求められるのです。 チーム開発の改善 SDDは、チーム開発にも大きな改善をもたらします。 知識の蓄積と共有 が可能になります。仕様が文書として残るので、「なぜこの設計になっているのか」「どういう経緯でこの技術を選定したのか」が後から分かります。新しいメンバーが参画しても、仕様を読めば素早くキャッチアップできます。 品質の向上 も期待できます。予測可能な出力により、「期待と違う」というギャップが減ります。レビュー可能な変更により、仕様レベルでのレビューが可能になります。追跡可能な履歴により、問題が発生したときに、どの変更が原因かを特定しやすくなります。 まとめ この一年の学びを、3つのポイントにまとめます。 仕様は新しいソースコード AIとの協業において、明確な仕様が最も重要です。コードそのものよりも、「何を作るか」を定義する仕様の方が価値を持つ時代になりました。仕様さえあれば、AIがコードを生成してくれます。逆に、仕様がなければ、AIは迷走します。 AIとの協業には構造が必要 Vibeコーディングから脱却し、予測可能な開発へ移行する必要があります。感覚的にコードを書くのではなく、構造化されたプロセスでAIと協業することで、品質と生産性の両立が可能になります。 AIに振り回される開発から、AIを使いこなす開発へ 仕様駆動開発(SDD)により、より良いソフトウェアを効率的に構築できます。AIは強力なツールですが、それを使いこなすのは人間です。明確な仕様を定義し、AIを適切に操縦することで、真の生産性向上が実現されます。 さいごに 今回は試行錯誤を重ねる中で、今年になって流行りだした「仕様駆動開発(SDD)」と実現するためのツールについて書きました。今年は業務内外で学んだ生成AIツールやAzureリソースに関することなど幅広い内容のブログを投稿できたと思います。これからも業務関係なく学んだ内容を投稿していこうと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post もうAIに振り回されない!OpenSpecで実現する予測可能なAI開発 first appeared on SIOS Tech. Lab .
アバター
こんにちは、サイオステクノロジーの佐藤 陽です。 「SIOS社員が今年一年で学んだこと」のアドベントカレンダー3日目です。 今回は、技術そのものというよりも、IT技術コミュニティの「運営」の話について書いていきます。 私は、2025年2月からJAZUG(Japan Azure User Group)静岡支部である「JAZUG Shizuoka」の運営を始めました。 自分は今年1年、「アウトプット力を更に高める」をテーマに動いてきており、その中核になったのが、このJAZUG Shizuokaの立ち上げでした。 運営を始めてから、気づけば1年弱が経ち、これまで3回のイベントを開催してきました。 第1回 JAZUG Shizuoka (2025年2月) 第2回 JAZUG Shizuoka (2025年6月) 第3回 JAZUG Shizuoka (2025年11月) 地方(静岡)でIT技術コミュニティを再興し、運営することで見えてきた「苦労」と、 それ以上に大きかった「メリット」について、振り返りを兼ねてまとめたいと思います。 地方でエンジニアをしていて「何か新しいことを始めたい」と思っている方の参考になれば幸いです。 なぜ静岡支部を立ち上げたのか? 東京では連日のように盛んなITイベントが開催されています。 しかし、静岡に住んでいると、時間やお金の都合で頻繁に参加することはできません。 「参加したいけれどできない」というもどかしさが常にありました。 オンラインで参加できるイベントもありますが、どこか受け身になってしまい、なかなか満足のいく体験には至っていませんでした。 それでも、エンジニアとして成長できる場として技術コミュニティへの強い憧れがありました。 もちろん静岡にもいくつか技術コミュニティはありますが、なかなか自分にマッチするものが見つからず…。 Azureコミュニティも以前は静岡に存在していたのですが、活動が休止している状態でした。 そんな折、ひょんなことからその以前の静岡のAzureコミュニティの方とつながる機会があり、そこからの流れでJAZUG本体の方とも繋がって、色々とお話をする機会をいただきました。 その過程で、 ないなら、自分がやってしまえばいいんだ。 と思い立ち、JAZUG Shizuokaの運営をスタートさせました。 初回イベント 意気込んで始めたものの、現実はそう甘くはありませんでした。 イベント公開後も想像していたよりも集まりは悪く、集客の難しさを痛感したスタートでした。 そのため会社の同僚や、知人のエンジニアに片っ端から声をかけて、なんとか最低限の参加者を募ることができました。 ただ、嬉しい誤算もありました。 参加者はなかなか集客に苦労しましたが、 登壇者に関しては、一般公募でLT(ライトニングトーク)枠が、すぐに定員に達しました。 地方にも、アウトプットしたい熱意を持ったエンジニアは確かにいる! と実感できたことは、運営を続ける大きなモチベーションになりました。 そんなこんなで初回のイベントは、参加者の皆さんのご協力もあり、大きなトラブルもなく終えることができました。   そこから第2回・第3回の開催へとつながっています。 「現地開催のみ」にこだわる理由 今の時代、オンライン配信を併用するハイブリッド開催が主流かもしれません。 オンラインにすれば全国から参加でき、集客人数も稼ぎやすいかと思います。 しかし、JAZUG Shizuokaでは あえて「現地開催のみ」 にこだわっています。 これは、オンライン要素があることで地方支部としての存在意義が薄れてしまうと考えたからです。 実際、現地に集まった参加者同士で話すと、 「あ、あの会社の方なんですね!」 といったローカルな共通点が見つかったり、地元のエンジニア事情などの「濃い話」で盛り上がったりすることが多々ありました。 これは、現地開催だからこそ生み出せた価値だと思っています。 そして今後もこの点は継続していきたいと思っています。 運営して得られたもの エンジニアとして、運営を通じて得られたメリットは非常に大きかったです。 1. 技術的な視野の広がり 自分ひとりで仕事をしていると、どうしても業務で触る機能や領域に知識が偏ってしまいます。 もちろん参加者として話を聞くだけでも勉強になりますが、運営(特に司会進行)を担うことで、「登壇者の話を誰よりも理解して、会場に橋渡ししよう」という良い意味でのプレッシャーが生まれました。 その結果、ただ漫然と聞くのではなく、他社の活用事例や普段触らないAzureの機能についても、以前より深く、自分事としてキャッチアップする姿勢が身につきました。 今後の個人的な課題 これに関連して、運営(司会)としては、LTで登壇してもらった後に、 「ありがとうございました。〇〇の技術って、やっぱり××なんですね。」 といった一言気の利いたコメントをしたいのですが、自身の技術力不足で、なかなかうまくコメントできないことも多くあります。 このあたりからも、やはり浅く広くでも知識を持っておきたいなと感じています。 2. コネクション 運営をするにあたって、今回であればJAZUGの方々とのつながりを持てたことが大きかったです。 また、X(旧Twitter)などで公募した際には、Microsoftの人や、界隈で著名な方にもリアクションをいただきました。 東京のITイベントに参加した際にも「あのJAZUG Shizuokaの!」といったことがあったりもしました。 こうしたつながりの一本一本はまだ細い線かもしれませんが、いつか大きなものにつながっていくのではないかと感じています。 3. 「場づくり」というスキル 技術力(ハードスキル)だけでなく、チームの成果を最大化する「場づくり」の力(ソフトスキル)の大切さを痛感しています。 運営を通じて必要となる「参加者が発言しやすい空気感を作る力」や「人を巻き込む力」は、そのままチームマネジメントにも通じるものがあると思います。 また、サードプレイスという、いつもとは異なる環境でこのような経験が出来ることは自身のキャリアに活きてくる部分と感じています。 まだまだ自分自身として未熟な部分ではありますが、このスキルの重要性を感じられたことは非常に大きな収穫であると感じています。 4. ITイベントへの参加率向上 当たり前ですが、運営メンバーなのでイベントには毎回参加します。 さらに、運営側の特権として、開催時期や場所、時間帯などをある程度自由に決められます。 自分は子供も小さく、なかなか関東(への遠征や、夜遅くに開催されるイベントへの参加が難しい状況です。 そういった場合、「自分が参加できる日時・場所」でイベントを開催してしまえばよいのです。 これはある種の職権乱用かもしれませんが、自分が確実に参加できる条件で場を作ることで、結果として自分自身の技術イベント参加率は確実に上がりました。 今後について これからは「細く長く」続けていきたいと思っています。 無理に規模を拡大するのではなく、継続することで信頼を積み重ねていきたいです。 願わくば、このコミュニティをきっかけに地元の企業同士のコラボレーションなどが生まれたら、最高だなと考えています。 ということで、是非JAZUG Shizuokaへのご参加の方お待ちしております! 開催のお知らせについては connpass や X を要チェックです! 最後に 地方在住で、なかなか参加するコミュニティなどが無くてもどかしく思っている方へ! いっそのこと、自分でコミュニティを立ち上げてしまうのはどうでしょうか? 地方でコミュニティを運営するのは、確かに集客などの面で大変です。 ですが、そこで得られる 繋がりや、運営の経験は、何物にも代えがたい資産になると思います。 今ではConnpassで公開するだけでイベントを開催できますし、SNSを利用して無償で宣伝も行えます。 仮に参加人数が集まらなかったり、うまくいかなくてもリスクはほとんど無いかと思います。 いずれ仲間はきっと見つかりますし、エンジニアとしての世界が間違いなく広がると思います。 是非検討してみてください!ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 1人がこの投稿は役に立ったと言っています。 The post 地方でIT技術コミュニティを1年間運営して得たもの first appeared on SIOS Tech. Lab .
アバター
こんな方へ特におすすめ これからエンジニアとしてのキャリアをスタートさせる方 未経験からエンジニアを目指しているけれど、不安を感じている方 IT業界やエンジニアという職業に興味がある、学生や他業種の方 概要 こんにちは。サイオステクノロジーのはらちゃんです。 「SIOS社員が今年一年で学んだこと」のアドベントカレンダー2日目です!記念すべき10本目のブログ執筆となります!! 早いもので、新卒で入社してから1年が経ちました。 今回は、この1年間どんな風に過ごしたか、何を学んだのか一緒に振り返っていきます。 私のスタート地点 私は大学時代、機械工学を専攻していました。普段は材料力学や流体力学といった、物理的なモノを相手にする毎日。そんな私がITエンジニアとして新卒入社したのですから、まさに異世界への挑戦でした。 ただ、まったくプログラミング言語に触れたことがないわけではありませんでした。研究室ではC#を扱い、ゲーム開発のようなことをしていました。そのため、幸いにも「プログラミング」という行為自体への抵抗感はありませんでした。 漠然と作っていくことの楽しさを感じていて、将来も型にハマらない自由な仕事をしたいと考えるようになりました。 入社直後 最初の壁 入社後最初の3カ月は、配属前の全体研修期間でした。ここでは主に、社会人としてのビジネスマナーや、エンジニアになるためのIT基礎知識を学びます。 私はここで「学生」と「社会人」のマインドセットの違いを強く感じました。 例えば、このような違いがあります。 学生時代は、与えられた課題に対して正解を出すこと、あるいは自分一人が納得できる成果物を作ることがゴールでした。しかし、社会人では「価値を生み出すこと」「チームで成果を出すこと」が求められます。   学生 社会人 評価基準 テストの点数 個人の研究成果 チームへの貢献度 ビジネス的な価値 時間感覚 比較的自由 コスト意識 責任の範囲 自分の行動範囲内 失敗しても自分が困るだけ 組織全体に影響が及ぶ プロとしての責任 コミュニケーション 仲の良い友人 年齢・立場の異なる多様な人 報告・連絡・相談の徹底 特に「報連相」の重要性は、頭で理解していても実践するのは難しく、最初はタイミングや伝え方によく戸惑いました。この期間に、技術者である前に一人のビジネスパーソンとしての基礎を叩き込まれたと感じます。 実務 第二の壁 いよいよSL(部署)に分かれて業務をしようというとき、ここで「趣味」と「仕事」の違いを感じました。 私は、大学の情報系学科で学ぶような「情報の基礎知識」がまったくありませんでした。インフラ、ネットワーク、OSなどの基盤知識がほぼゼロで飛び交う専門用語がまるで呪文のように聞こえました。 さらに、これまで一人でコードを書いていたため、チーム開発の経験が皆無でした。「Gitっておいしいの?」という状態で、バージョン管理という概念すらありませんでした。 「一人で動くコードが書ける」ことと、「プロとしてチームでシステム開発ができる」ことは、全くの別物だったのです。 当時の私のできること、できないことは明確に分かれていました。 できること コードを見ること、書くことへの免疫 モノづくりに対するポジティブなモチベーション できない、知らないこと 情報の基礎知識 チーム開発の作法 気付き はじめは疑問だらけでした。 エラーログを見ても何が書いてあるか分からない。先輩に質問しようにも、何が分からないのかが分からない。 しかし、もがき続ける中で、いくつかの重要な「気付き」がありました。 「分からない」を認める勇気 一人で抱え込んでも事態は悪化するだけだと痛感しました。勇気を出して「ここが分かりません」と発信したとき、先輩方は嫌な顔一つせず、丁寧に教えてくれました。 暗記ではなく「調べ方」を知る 膨大なITの知識を全て暗記するのは不可能です。重要なのは、エラーが出たときに「どういうキーワードで検索すればよいか」という、問題を解決するための「調べ方」を身につけることだと気付きました。 知識が知恵になる 最初はバラバラに見えていた知識(例えばLinuxコマンドとGitの操作)が、実務の中で繋がる瞬間が訪れます。  「あ、あの時のあれは、こういうことだったのか!」 というアハ体験。この積み重ねが、成長の実感に繋がりました。 また、技術との向き合い方だけでなく、チームで仕事をする上でのコミュニケーションについても、大きな意識の変化がありました。 仕事としてのコミュニケーション 「報連相」もたしかに重要ですが、今大切なのは「ザッソウ」だと感じました。 雑談 他愛のない話ができる人と仕事をする環境であれば、連絡や質問もスムーズです。 相談 上記のような安心感があれば、躊躇することなく人に相談できます。 チーム開発では、互いのタスクを把握していることで全体の進捗を把握し、納期を意識したスケジュール管理が行えます。 1人で抱え込むことは、チームにとっても当人にとっても利益のないことです。 とにかくやってみる 実プロジェクトが始まる前に、自己学習としてOJTに取り組みました。 そこでは「何をやりたいか」を重視していて、私はただひたすらに作りながら学ぶことを行いました。 具体的には、Webアプリケーション開発の全体像を把握するために、フロントエンドからデータベースまでの一連の流れを網羅的に学習しました。 私が取り組んだ基本的な構成は以下の図の通りです。 ユーザーが触れる画面(フロントエンド)には React 、データの処理やビジネスロジックを担うサーバーサイド(バックエンド)には Python 、そしてデータを保存するデータベースには MySQL を選定しました。 これらを組み合わせて一つのアプリケーションとして動作させることで、それぞれの役割や連携の仕組みを肌で感じることができ、Web開発の基礎体力をつける良い機会になりました。 また、この時期に並行して基本情報技術者試験の学習を行ったことも、業務で触れる知識を体系的に理解する助けになりました。「業務に絡めて理解する」ことが、資格取得への近道だと感じました。 上記のような開発をしながら、ライブラリやツールを活用してみたり、考えなければならないリスクに対する対策を考えてみたりと興味を持つことは強みになります。 このように、さまざまな技術に触れる時間のなかで、RAGを扱ったシステム開発が最も印象的です。 RAGとは、特定の情報源(社内データベース等)から関連情報を検索し、それを活用して大規模言語モデルがテキストを生成する技術です。AIが事実に基づかない情報を生成する現象(ハルシネーション)の対策の1つと言えます。 具体的なシステムの内容については こちら のブログで書いているので覗いてみてください。 ここで私は自身のAI相棒を作ろうと奮起しています。言語モデルはローカルで動かせる軽量さを重視し、Gemma(ジェマ)を用いています。 今、できること 1年前の自分と比べて、少しは胸を張って「成長した」と言えるようになりました。 技術面 チーム開発への参加 Gitを使ったバージョン管理、プルリクエストの作成、コードレビューの指摘対応などが、日常的な業務としてできるようになりました。 問題解決能力の向上 エラーが発生してもパニックにならず、ログを読み解き、仮説を立てて調査し、ある程度の問題は自己解決できるようになりました。 全体像の理解 自分が担当している機能が、システム全体の中でどのような役割を果たしているのか、アーキテクチャを意識して開発できるようになりました。 マインド面 学習意欲の向上 「分からない」ことが「怖い」ことではなく、「新しいことを知るチャンス」だと捉えられるようになりました。技術への好奇心が恐怖心を上回るようになりました。 プロとしての自覚 自分の書いたコードがサービスとして世に出て、ユーザーに使われることの責任感を持つようになりました。 他者への貢献意欲 まだまだ教えてもらうことが多いですが、新しく入ってくる後輩や、同じように悩んでいるチームメンバーに対して、自分の知見を共有したいと思うようになりました。 過去の自分へ伝えたいこと 1年前の、不安で押しつぶされそうだった自分に声をかけられるなら、こう伝えたいです。 周りの同期と比べて焦る必要はない。 一つひとつ向き合って、手を動かし続けていれば、必ず点と点が繋がる瞬間が来る。 完璧を目指さなくていい。 昨日の自分より少しでも前に進んでいれば、それで十分すごい。 これは、これから未経験でエンジニアの世界に飛び込もうとしている皆さんへのメッセージでもあります。 知識の有無よりも、「学び続ける姿勢」と「素直さ」があれば、絶対に大丈夫です。 まとめ 機械系出身、IT知識ゼロからのスタート。怒涛のような1年でした。 もちろん、まだまだ半人前で、学ぶべきことは山のようにあります。しかし、この1年間で得た「分からないことを乗り越える力」と「作る楽しさ」は、これからのエンジニア人生における最強の武器になると確信しています。 2年目も、初心を忘れず、技術を楽しみながら成長していきたいと思います! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 1人がこの投稿は役に立ったと言っています。 The post 基礎知識ゼロから新卒1年|仕事としての技術とマインド first appeared on SIOS Tech. Lab .
アバター
PS SLの佐々木です。 SIOS Tech Labアドベントカレンダー1日目になります! 今年からOSS推進フォーラムの鳥観図ワーキンググループのリーダーとして活動しています。 そこでOSS鳥観図WGの活動を今回は紹介させていただこうと思います。 OSS鳥観図ワーキンググループとは 「OSSを使いたいけど、○○の分野ではどのOSSがよく使われているのだろう?」 OSS鳥瞰図とは、こういったOSS初心者を手助けするために複雑多岐にわたるOSSを、視覚的に俯瞰できるようまとめたものです。鳥瞰図WG (旧クラウド技術部会)では世論の活用状況などを観察し、2014年からOSS鳥瞰図を毎年更新しています。 活動の基本方針 OSS利用者が、システムにOSSを採用・導入する際の手引きとなる情報を提供する OSS鳥瞰図を最新版に更新し、 OSSの選定をより安心感をもって、かつ短時間にできるよう手助けをする OSSに関する技術動向、日本国内事例等を広く集め、様々な形でOSSを活用する人たちに、プラスとなる情報を提供する 活動内容 鳥観図改版活動 OSS鳥観図WGでは毎年公開されているOSS鳥観図の改版を行うため、月に一度鳥観図に掲載するOSSの見直しを行っています。 具体的には鳥観図の新規追加、削除、カテゴリーの変更などを有識者たちで集まり議論し、来年度に掲載するOSSを決定しています。 新規追加では今年注目度が集まっているOSSの選定を行いWG内で議論し掲載するか決定しています。 削除やカテゴリー変更では掲載中のOSSにライセンスの変更がないか、機能が拡張され現在属しているカテゴリーが適切ではないのではないか、OSSの開発活動が活発に行われているか、セキュリティーで深刻な脆弱性が報告されていないかなど様々な観点で掲載中のOSSを検討し来年度の鳥観図を確定していきます。 OSS鳥観図宣伝活動 OSS鳥観図では様々なオープンソースのイベントに参加し発信活動を行っています。 OSC Open Source Summit etc… WG参加メンバー ワーキンググループには多くのメンバーが参加しており、大手のベンダーやOSSコミュニティ、参加者まで多岐にわたります。 鳥観図WGへの関わり方(コントリビューション方法) OSS鳥観図ワーキンググループでは参加メンバーを募集しています。 活動内容は上記記載した通りですが、月に一度2時間程度のWGでのディスカッションと担当カテゴリのOSSの調査がメインの活動になります。 もし活動に興味のある方はka-sasaki@sios.comまでご連絡ください。 またこの活動以外にも実際に鳥観図を見て、追加してほしいOSSの提案や脆弱性報告など様々な提案をGithub Issueで募集しています。 是非とも貴重なご意見お待ちしています。 https://github.com/ossforumjp/oss-choukanzu/issues 鳥観図WGのホームページ https://ossforum.jp/index.php/choukanzu-wg/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OSS鳥観図ワーキングループの活動紹介 first appeared on SIOS Tech. Lab .
アバター
はじめに 前回は、StatefulSetと永続ボリューム(PV/PVC)を使い、データが消えないDBコンテナを起動しました。 しかし、データベースはアプリケーションから接続されて初めて価値があります。そのため今回はアプリコンテナとDBコンテナの接続方法を学びます。 前提条件 Kubernetesで、Pod同士をどうやって通信させるのか仕組みを知りたい方 DBコンテナを立てることはできたが使用出来ていない状態の方 アプリコンテナとDBコンテナを接続するための基本概念 コンテナ同士を接続する方法はいくつかありますが、Kubernetesでは推奨される接続方法が決まっており、単純な接続方法ではうまくいきません。特にDB接続では、ポート番号や認証情報(Secret)をアプリコンテナに適切に渡す必要があるほか、DBコンテナの動的なスケーリングや再起動によるIPアドレスの変動が接続安定性の課題となります。 このような固有の課題を解決するためには、Kubernetesのネットワーク層におけるServiceやDNSの仕組みを理解することが重要です。この記事では、DB接続における安定性を向上させるために、ServiceとDNSの利用方法に焦点を当て、その役割や実践的な活用法を解説します。 直接接続の問題点 最も単純な接続方法は、DBコンテナ(Pod)のIPアドレスを調べ、アプリの設定ファイルに直接記述する方式です。しかし、この方法には致命的な問題があります。Podは再起動するとIPアドレスが変わってしまうという点です。ノードの障害、設定変更による再デプロイ、負荷分散による再スケジューリングなどの問題が発生すると、古いPodは破棄され、新しいPodが作られます。この時、IPアドレスは変わってしまいます。 直接接続ではDBが再起動するたびにアプリの設定ファイルを書き換え、再起動しなければならず手間がかかります。 Serviceの仕組み Kubernetesでは、PodのIPアドレスが変動する問題を解決するために「Service」というリソースを利用します。Serviceは一意の名前を持ち、内部DNSを介してアクセス可能です。これにより固定的なDNS名を提供することができ、アプリケーションはこのDNS名を使用して安定した通信を実現できます。 KubernetesのDNSの仕組み Serviceを利用することで、PodのIPアドレスが変わる問題を解決できます。しかし、ServiceのIPアドレスをアプリケーションに設定する手間が残ります。この問題を解決するのがKubernetesのDNSです。通常、DNSはドメイン名とIPアドレスを対応させる役割を持っています。一方、Kubernetesクラスターには専用のDNSサーバーが標準で組み込まれており、Service名とIPアドレスを対応づける機能を提供します。Kubernetesでは、Serviceを作成すると、そのサービス名とIPアドレスの対応が自動的にDNSサーバーに登録されます。 この仕組みによりKubernetesでのPod間の接続は完全修飾ドメイン名(<Service名>.<Namespace名>.svc.cluster.local)を使用して実現できます。サービス名とネームスペース名を指定することで、Pod間通信が可能になります。 また、本記事ではDNSの仕組みの理解のために完全修飾ドメイン名を使用していますが、同じネームスペース内に存在するアプリケーションからServiceに接続する際にはサービス名だけで接続が出来ます。 YAMLファイルの作成例 これまで、アプリコンテナとデータベースコンテナの接続方法について解説しました。ここからは、具体的なYAMLファイルの例を示し、ServicesやKubernetesのDNSをどのように設定するのかについて解説します。 DBコンテナ側の設定 DBコンテナの設定(接続されるコンテナ) apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: "mysql-service" replicas: 1 selector: matchLabels: app.kubernetes.io/name: mysql # (A) Serviceはこのラベルを基準にPodを探す。 template: metadata: labels: app.kubernetes.io/name: mysql # (A) Serviceに見つけてもらうためのラベル。 spec: containers: - name: mysql-container image: mysql:8.0 env: # ... 省略 ... ports: - containerPort: 3306 # (B) このPodが待ち受けるポート。ServiceのtargetPortと一致させる。 volumeClaimTemplates: - metadata: name: mysql-storage spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "standard" resources: requests: storage: 1Gi Serviceの設計(接続の窓口) apiVersion: v1 kind: Service metadata: name: mysql-service # KubernetesのDNSに登録される名前。この名前を使って他のコンテナからアクセス可能になる。 spec: selector: app.kubernetes.io/name: mysql # (A) このラベルを持つPodを探す。 ports: - protocol: TCP port: 3306 # クライアントが接続するポート番号。 targetPort: 3306 # (B) Podのコンテナが待ち受けているポート。StatefulSetのcontainerPortと一致させる。 metadata.name: mysql-service :サービス名がKubernetesのDNSに登録されます。このサービス名とネームスペース名があれば他のコンテナから接続ができます。 selector:Serviceが接続先のPodを決定するためのラベルセレクターです。ここでは、`app.kubernetes.io/name: mysql` というラベルが付けられたPodを対象とします。このラベルセレクターを使用してServiceは指定されたラベルを持つすべてのPodに接続します。 port: 3306:クライアントが接続するポート番号です。アプリケーションはこのポートに向けて通信します。 targetPort: 3306:Serviceが受け取った通信を転送するPodの内部ポート番号です。ここでは3306 番ポートに転送されます。 アプリコンテナ側の設定 apiVersion: apps/v1 kind: Deployment metadata: name: wordpress labels: app: wordpress # Podの識別用ラベル。 spec: # ... 省略 ... template: metadata: labels: app: wordpress spec: containers: - image: wordpress:6.2.1-apache name: wordpress env: - name: WORDPRESS_DB_HOST value: mysql-service.default.svc.cluster.local # 完全修飾ドメイン名を使用してDNSで解決する。 # ... 省略(DBのパスワードやユーザーの設定) ... - name: DB_PORT value: "3306" value: mysql-service:Serviceの名前を元にDNSを使ってIPアドレスを解決し、そのIPアドレスに対して接続を試みるための設定です。 おわりに 今回は、ServiceとDNSを活用したコンテナ同士の接続方法について解説しました。これらの技術を利用することで、PodのIPアドレスが変動しても影響を受けることなく、安定した接続を実現できます。  次回からは、Kubernetes内部のデータベースコンテナを外部に公開する方法について、2回にわたり解説していきます。 参考文献 https://kubernetes.io/docs/concepts/services-networking/service/ https://kubernetes.io/ja/docs/concepts/services-networking/dns-pod-service/ https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post コンテナDB実践シリーズ④:アプリコンテナからDBコンテナへの接続 first appeared on SIOS Tech. Lab .
アバター
今号では、sftp コマンドを使ったファイル転送の方法について説明します! sftp とは sftp とは SSH File Transfer Protocol の略であり、暗号化された通信によって安全にファイルを送受信することができる仕組みです。 以前は ftp によるファイルの送受信が主流でしたが、通信を暗号化する仕組みがないため、内容が盗聴される可能性がありました。 そこで、すべてのデータを暗号化して送信することができる sftp が使用されることになりました。 主な用途としては、システム間でのファイルの送受信や、Web サーバへ各コンテンツ (html、css、画像ファイル) のアップロードなどがあります。 なお、今回は Linux や Windows 上のターミナルで sftp コマンドを使う前提で説明します。 基本の書式 リモートサーバへ接続 sftp ユーザ名@ホスト名 の書式で実行します。 例: $ sftp ruser@172.30.10.10 ruser@172.30.10.10's password: Connected to 172.30.10.10. sftp> ※パスワード認証の場合、リモートユーザのパスワードが求められます。 リモートサーバから切断 exit もしくは bye を実行します。 例: sftp> exit 現在のディレクトリ (リモート側) を表示 pwd コマンドを実行します。 例: sftp> pwd Remote working directory: /home/ruser 現在のディレクトリ (ローカル側) を表示 lpwd コマンドを実行します。 例: sftp> lpwd Local working directory: /home/luser ファイル一覧 (リモート側) を表示 ls を実行します。 例: sftp> ls 1.log 2.log 3.log dir1 dir2 ruser-file -l オプションを付けると、各ファイルやディレクトリの詳細を表示します。 sftp> ls -l -rw-rw-r-- 1 ruser ruser 0 Nov 17 01:04 1.log -rw-rw-r-- 1 ruser ruser 0 Nov 17 01:04 2.log -rw-rw-r-- 1 ruser ruser 0 Nov 17 01:04 3.log drwxrwxr-x 2 ruser ruser 6 Nov 17 01:06 dir1 drwxrwxr-x 2 ruser ruser 6 Nov 17 01:06 dir2 -rw-rw-r-- 1 ruser ruser 0 Nov 17 01:04 ruser-file ファイル一覧 (ローカル側) を表示 lls を実行します。 例: sftp> lls 1l.log 2l.log 3l.log local-dir luser-file -l オプションを付けると、各ファイルやディレクトリの詳細を表示します。 sftp> lls -l total 0 -rw-r--r--. 1 luser luser 0 Nov 17 01:05 1l.log -rw-r--r--. 1 luser luser 0 Nov 17 01:05 2l.log -rw-r--r--. 1 luser luser 0 Nov 17 01:05 3l.log drwxr-xr-x. 2 luser luser 6 Nov 17 01:07 local-dir -rw-r--r--. 1 luser luser 0 Nov 17 01:05 luser-file ディレクトリ (リモート側) を移動 cd ディレクトリ名 の書式で実行します。 例: sftp> cd dir1 ディレクトリ (ローカル側) を移動 lcd ディレクトリ名 の書式で実行します。 例: sftp> lcd local-dir 続いて、一番重要なファイル転送についてのコマンドです。 ファイルのダウンロード (リモート→ローカル) get リモート側のファイル名 の書式で実行します。 例: sftp> get ruser-file Fetching /home/ruser/ruser-file to ruser-file sftp> lls 1l.log 2l.log 3l.log local-dir luser-file ruser-file リモート側のファイル名の後に 任意のファイル名 を付けると、そのファイル名で保存されます。 sftp> get ruser-file ruser-file.bkp Fetching /home/ruser/ruser-file to ruser-file.bkp sftp> lls 1l.log 2l.log 3l.log local-dir luser-file ruser-file.bkp ファイルのアップロード (ローカル→リモート) put ローカル側のファイル名 の書式で実行します。 例: sftp> put luser-file Uploading luser-file to /home/ruser/luser-file luser-file 100% 0 0.0KB/s 00:00 sftp> ls 1.log 2.log 3.log dir1 dir2 luser-file ruser-file リモート側のファイル名の後に 任意のファイル名 を付けると、そのファイル名で保存されます。 sftp> put luser-file luser-file.bkp Uploading luser-file to /home/ruser/luser-file.bkp luser-file 100% 0 0.0KB/s 00:00 sftp> ls 1.log 2.log 3.log dir1 dir2 luser-file.bkp 複数ファイルの一括ダウンロード (リモート→ローカル) mget リモート側のファイル名パターン の書式で実行します。 例: sftp> mget *.log Fetching /home/ruser/1.log to 1.log Fetching /home/ruser/2.log to 2.log Fetching /home/ruser/3.log to 3.log sftp> lls *.log 1.log 2.log 3.log 複数ファイルの一括アップロード (ローカル→リモート) mput ローカル側のファイル名パターン の書式で実行します。 例: sftp> mput *.log Uploading 1l.log to /home/ruser/1l.log 1l.log 100% 0 0.0KB/s 00:00 Uploading 2l.log to /home/ruser/2l.log 2l.log 100% 0 0.0KB/s 00:00 Uploading 3l.log to /home/ruser/3l.log 3l.log 100% 0 0.0KB/s 00:00 sftp> ls *.log 1l.log 2l.log 3l.log sftp コマンドのオプション sftp コマンド の基本的なオプションをご説明します。 ※すべてのオプションはご紹介せず、よく使用されると考えられるものを抜粋しています。 -i 秘密鍵のファイル 公開鍵認証で接続する場合、-i の後に使用する秘密鍵のファイルを指定します。 $ sftp -i ~/.ssh/id_rsa ruser@172.30.10.10 -P ポート番号 SSH/SFTP が 22番ポート (デフォルト) 以外で動作している場合、該当するポート番号を指定します。 $ sftp -P 10022 ruser@172.30.10.10 -v 接続時の詳細なデバッグ情報を表示します。 なお、このオプションには 3段階あり、-vv にするとさらに詳細なデバッグ情報が、-vvv にすると最も詳細なデバッグ情報が表示されます。 $ sftp -v ruser@172.30.10.10 次号について 次号では、sftp と同じくファイル転送を担う rsync についてご紹介します! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!sftp コマンドを使ったファイル転送 first appeared on SIOS Tech. Lab .
アバター