サイオステクノロジー(Tech.Lab)のブログ - TECH PLAY

TECH PLAY

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

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

全739件

はじめに ども!今月はがっつりと開発期間をいただいて、社内で活用できるサービスを作成しつつ、AIとの開発検証を進めている龍ちゃんです。作るものが多くてあっちにフラフラこっちにフラフラって感じです。 今回は、「 Claude Code革命!3フェーズ開発で効率的な開発:計画→実装→検証術 」で提唱した「計画ドキュメント」を用いての開発を3カ月ほど続けたので、そこに対する知見を書いていこうと思います。 結論は「計画ドキュメント」ってめちゃくちゃ大事じゃね?ってお話です。 問題:AIに丸投げすると何が起きるか 技術選定を任せる危険性 開発を進めていく中で、最も課題となったのが「AIに技術選定を委ねてしまう」という問題でした。 具体的な例として、 私はSWRで全ての処理を自動生成しようと試みていました。SWRは本来データフェッチングに特化したライブラリですが、CRUD操作の全てをSWRで解決しようとしていたのです。これは設計思想から考えると適切ではありませんでした。 CRUDの4つの要素のうち、SWRが最適化されているのは主にRead(データ取得)の部分です。Create、Update、Deleteの3/4については本来の用途から外れているにも関わらず、統一性を重視して全てSWRで実装しようとしていました。 人間の開発者であれば「SWRの実装が複雑になるようであれば、素直にAxiosを使用した方が良い」という判断ができます。しかし、AIにはこうした経験に基づく技術的判断や、ライブラリの適切な使い分けに関する感覚が不足しているようです。 龍ちゃん システムプロンプトで「SWRを絶対使うように」って書いていたので、技術選定をしたのは人間なのですがそれに対する課題などの指摘は特にないってのが問題ですね。 AIの限界:誤字脱字と文脈の理解 プロンプトを通じたやり取りで発生する問題も重要な課題でした。 入力に誤字脱字が含まれている場合、AIはそれを修正することなく処理を継続してしまいます。技術用語の誤入力などがあっても、人間であれば文脈から推測して修正できるような内容でも、AIは字面通りに解釈して間違った方向に進んでしまうことがあります。 この結果、想定していたアーキテクチャから逸脱した実装が生成されたり、設計方針に一貫性がなくなったりする問題が発生しました。 具体例として、README.mdに「SWRを必ず使用すること」という記述があったのですが、これが問題の原因となりました。Orvalの設定を適切に調整すれば回避できた問題でしたが、全てのエンドポイントに対してAxiosとSWRの両方のクライアントが生成される状況で、AIは一貫してSWRを選択し続けていました。 根本原因:意思決定の不在 これらの問題の本質は、 人間が行うべき意思決定をAIに委ねてしまっている 点にあります。 人間の開発者は、明文化されていない暗黙知に基づいて技術的判断を行うことがあります。「この技術領域では一般的にこのようなアプローチを取る」といった、体系化されていない経験則や業界標準に関する知識です。 こうした暗黙知は、各開発者の経験や学習によって蓄積されたものですが、現在のAIには十分に備わっていないと感じています。もちろん、私の技術力が不足しているため、AIの能力を十分に引き出せていない可能性もありますが、この差を埋める仕組みが必要です。 その仕組みこそが、 計画ドキュメント による意思決定の明文化なのです。 解決策:計画ドキュメント = 意思決定の場 人間同士の協働 vs AI協働の違い 人間同士での開発とAI協働での開発では、「暗黙知の共有レベル」に大きな差があります。 人間同士での協働の場合: 共通の技術的背景知識を前提とした議論が可能 「一般的にはこのようなアプローチを取る」という共通認識 文脈を理解した柔軟な修正と提案 暗黙の了解による効率的なコミュニケーション AI協働の場合: 明示的に指示された内容のみに基づく判断 技術的なベストプラクティスの理解が限定的 プロンプトの内容に対する忠実な実行 全ての判断基準の明文化が必要 つまり、AI協働においては 全ての意思決定プロセスを文書化 することが不可欠となります。 計画ドキュメントで決めること 計画ドキュメントで明文化すべき要素は、主に以下の4つです: 技術選定: 選定理由とともに、採用しない選択肢(禁則事項)についても記載 ライブラリ間の使い分け基準の明確化 例:SWRはデータフェッチ(Read)操作のみに使用し、CUD操作にはAxiosを使用する アーキテクチャ方針: フロントエンド・バックエンド間の責任境界 エラーハンドリングの統一方針 状態管理の方法と各層の責務 API設計: エンドポイントの命名規則と構造 レスポンス形式の統一ルール エラーレスポンスの標準フォーマット 実装方針: ディレクトリ構成とファイル配置のルール コンポーネント設計のガイドライン テスト方針とカバレッジ基準 意思決定と実行の分離 効果的なAI協働を実現するには、 意思決定フェーズと実行フェーズを明確に分離 することが重要です。 人間の役割: 何を作るか、どのような方針で開発するかを決定する AIの役割: 決定された方針に従って、実際のコードを生成・組み立てる この役割分担により、AIの長所である「高速で大量のコード生成」を活かしながら、人間の「経験に基づく技術判断」を適切に反映できるようになります。 計画の品質が成果物の品質を決定するのは開発の基本原則ですが、特にAI協働においては「計画ドキュメントがプロジェクトの成否を左右する」と言えるでしょう。 実行の標準化:パーツと自動生成 品質保証としてのパーツ化 実際の開発では、意思決定した内容を「パーツ」として標準化することで品質を保証できます。これはソフトウェア工学における品質管理の考え方と共通しています。 システム開発において、個々のコンポーネントの品質がシステム全体に与える影響は重大です。一つのコンポーネントに不具合があると、それがシステム全体の信頼性を損なう可能性があります。プログラムにおいては多少の技術的負債を抱えても稼働し続けることは可能ですが、基盤となるパーツがすべて品質に問題を抱えている場合は、深刻な影響が生じます。 特にフロントエンドを開発する際は、外部のAPIや自作のAPIをパーツとしてとらえることで、作業領域が明確化されます。 人間の役割: 作成すべき機能と要件を明確に定義する 使用するパーツの選択と品質基準の設定 パーツの妥当性と整合性を検証する パーツ/自動生成の役割: 実装方法を標準化し、一貫性を保つ コードの品質を一定レベルに維持する 再利用性を高め、開発効率を向上させる AIの役割: 定義されたパーツを適切に組み合わせて実装する ボイラープレートコードの大量生成を効率化 人間が決定した設計方針に従ってコードを構築する 実例:自動生成パイプライン 具体例として、OpenAPIスペックから型定義を自動同期するパイプラインを構築した際の事例をご紹介します。 // DTO定義(人間による意思決定) interface UserCreateRequest { name: string; email: string; role: 'admin' | 'user'; } // 型定義とAPI関数は自動生成 const createUser = async (data: UserCreateRequest) => { return axios.post<UserResponse>('/api/users', data); }; この実装において重要なポイントは、 DTO定義という設計判断は人間が行い、実行部分(型定義生成、API関数生成)は自動化 している点です。これにより、設計の一貫性を保ちながら実装効率を大幅に向上させることができました。 参考事例:Shadcn/uiのアプローチ Shadcn/uiは、UIコンポーネント開発において「パーツ化」の優れた事例を提供しています。 このライブラリが革新的な点は、UIコンポーネントを標準化された「パーツ」として提供し、開発者が「どのコンポーネントを使用するか」という意思決定に集中できる環境を作り出していることです。AIは「パーツを選択して適切に組み合わせる」という作業に集中でき、結果として開発効率と品質の両立を実現しています。 この考え方は、API接続層やビジネスロジック層にも応用可能であり、AI協働開発における有効なパターンとなり得ると考えています。 実践:意思決定を握る3原則 原則1:計画ドキュメントでの明文化 実施内容: 技術選定の理由を具体的かつ詳細に文書化 実装方針を明確で実行可能なレベルまで記述 暗黙知となっている判断基準の言語化 明文化の範囲について: 理論的にはどこまで詳細化しても構いませんが、コンテキスト量の制約があることを考慮する必要があります。特にClaude等のLLMを使用する場合、トークン制限により詳細すぎる文書は処理できなくなる可能性があります。このバランス調整は現在の技術的制約として受け入れる必要があります。 実践的な運用方法: バックエンドとフロントエンドを並行開発する場合、計画ドキュメントに加えて具体的な実装手順をToDo形式で管理することを推奨します。進捗を可視化することで、AIツールが予期せず停止した場合でも、明確な再開ポイントを確保できます。 原則2:パーツによる実行の標準化 実施内容: 再利用可能なコンポーネント・関数の設計と整備 API接続の標準化(型定義、エラーハンドリング含む) 開発ツール(Linter、Formatter等)の統一と自動化 品質保証の重要性: 個々のパーツの品質は、システム全体の安定性に直結します。不適切な設計のパーツを多数組み合わせると、保守性や拡張性に深刻な問題が生じる可能性があります。そのため、パーツ設計段階での品質基準の設定と検証が不可欠です。 原則3:検証による継続的改善 実施内容: 計画と実装結果の差分分析と記録 発見された問題点や改善点の体系的な蓄積 得られた知見の次回プロジェクトへの適用 現実的な視点の重要性: 完璧な計画ドキュメントや仕様書を最初から作成することは現実的ではありません。開発過程で「より良いアプローチが明確になる」ことは自然な現象です。 そのような状況では、変更の必要性を適切に判断し、修正された方針で実装を完了させることが重要です。完了後には計画と実装の差分を分析し、その経験を将来のプロジェクトに活かすことで、継続的な改善を図ることができます。 まとめ:意思決定は人間、実行はAI 本記事では、3ヶ月間のAI協働開発を通じて得られた実践的な知見をもとに、効果的な協働体制の構築について詳しく解説してきました。 重要ポイントの整理: 技術選定の主導権確保 – AIに技術的判断を委ねることのリスクと、経験に基づく適切な技術選択の重要性 計画ドキュメントによる意思決定の明文化 – 暗黙知の言語化と、全ての判断基準の明確化の必要性 意思決定と実行の明確な分離 – 人間とAIの適切な役割分担による効率化の実現 パーツ化による実行の標準化 – 品質保証と再利用性向上のための設計アプローチ 継続的改善による知見の蓄積 – 完璧性よりも学習と改善を重視したアプローチ 結論として 、現在のAI協働開発においては、 人間が意思決定を行い、AIが実行を担当する という役割分担が最も効果的であると考えられます。 AI技術は急速に進歩していますが、現時点では経験に基づく技術的判断や、コンテキストを考慮した柔軟な意思決定において、人間の能力に及ばない側面があります。一方で、大量のコード生成や、定められたパターンに従った実装作業においては、AIの方が高速かつ正確に処理できます。 この技術特性を理解し、適切な役割分担を実装することで、AI協働開発の真価を発揮することが可能になります。 実践への提案 AI協働開発を検討されている方は、まず「計画ドキュメント」の作成から始めることをお勧めします。初期段階では作成コストが高く感じられるかもしれませんが、中長期的には開発効率と成果物の品質において大幅な改善効果が期待できます。 この記事で紹介した3原則と実践的アプローチが、皆さんのAI協働開発プロジェクトの成功に寄与できれば幸いです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post AI協働開発の落とし穴回避!3ヶ月で実証した計画ドキュメントの価値 first appeared on SIOS Tech. Lab .
初めに ども!今月はAI開発にどっぷりな毎日な龍ちゃんです。今回は「 AIと爆速開発!Next.js×Nest.js型定義同期の自動生成パイプライン構築術 」で開発効率を上げたんですが、そこで起きた問題について原因究明と解決策を模索したので解説していこうと思います。 TL;DR Orvalで全APIエンドポイントにSWRフックを自動生成していたんですが、 バンドルサイズの肥大化 と 不要なオーバーヘッド が問題になってしまいました。 解決策 : client: "axios-functions" に変更して、Axios関数のみを自動生成。SWRは必要な箇所のみカスタムフック実装する方針に切り替えました。 結果 : 47ファイルの移行(4.2時間)で、バンドルサイズを20-30%削減できました! 問題の発見:便利すぎる自動生成の罠 最初はOrvalで全APIエンドポイントにSWRフックを自動生成する設定にしていました。便利だと思っていたんですよね。型安全だし、統一感もあるし。 でも2ヶ月ほど経った頃、ふと気づいたんです。バンドルサイズはどんどん肥大化していくし、mutation処理は無駄にSWRを経由しているし、コードは複雑になっていく一方。 何かがおかしい。 そこで改めて考え直してみました。SWRって、そもそも何のためのツールだったっけ?と。 SWRの本質を見つめ直す SWRは データ取得(Read)のために設計 されたライブラリです。名前の由来である「stale-while-revalidate」という戦略が示す通り、以下のような特徴があります: キャッシュ戦略による高速な表示 自動再検証(フォーカス時、再接続時など) 複数コンポーネント間でのデータ共有 これって、まさにCRUDのRead(データ取得)に最適化された設計なんですよね。 一方で、 CUD(Create/Update/Delete)はどうでしょうか? useSWRMutation というフックも用意されていますが、よく考えてみると一回限りのmutationにキャッシュ戦略は不要です。フォーム状態との統合も煩雑になりがちでした。 それなのに、全エンドポイント分のSWRフックを自動生成していたら、本質的には不要なコードが大量に生まれてしまっていたんです。 Before/After: Orval設定の変更 それでは、具体的にどう変更したのか見ていきましょう。 Before(旧設定) output: mode: "split" # ❌ ラッパー関数が生成される client: "swr" # ❌ SWRフック自動生成 # ... 問題点 : 全エンドポイント分のSWRフックが生成され、バンドル肥大化。mutationにも不要なSWRオーバーヘッドが発生していました。 After(新設定) output: mode: "single" # ✅ 直接エクスポート client: "axios-functions" # ✅ Axios関数のみ生成 # ... 改善点 : Axios関数のみを生成し、SWRは必要な箇所のみ手動で作成。バンドルサイズを20-30%削減できました。 シンプルですよね。でも、この変更が大きな効果を生んだんです。 自動生成の3つの問題 実際に移行作業を進めながら、自動生成のどこが問題だったのか明確になってきました。 1. 不要なオーバーヘッド 例えば、投稿を作成する処理を考えてみてください。これって一回限りのアクションですよね。キャッシュも再検証も不要なのに、SWRの状態管理オーバーヘッドが動いている。これは明らかに無駄でした。 2. バンドルサイズの肥大化 数字で見ると、問題の大きさがよくわかります: 項目 Before After 改善 自動生成フック数 41個 0個 完全削除 バンドルサイズ 100% 70-80% 20-30%削減 コード行数 ~2030行 ~800行 約60%削減 全エンドポイント分のSWRフックが生成されて、使わないものも含めて全部バンドルに入ってしまっていたんですね。 3. コンポーネント設計の硬直化 これが一番厄介でした。SWRの状態( isMutating , error )とフォームの状態( isSubmitting , validationErrors )が分裂してしまって、同期が複雑化していたんです。 実際にフォームを実装していると、「あれ、どっちのエラー状態を見ればいいんだっけ?」みたいなことが頻発していました。 解決策:適材適所のアプローチ そこで、シンプルな方針に切り替えました: ✅ Read(GET) → カスタムSWRフック ✅ CUD(POST/PUT/DELETE) → 直接Axios呼び出し それぞれ見ていきましょう。 パターン1: データ取得(カスタムSWRフック) データ取得には、SWRの恩恵を最大限活用します。 // hooks/useSeriesDrafts.ts import useSWR from "swr"; import { seriesDraftsControllerFindAll } from "@/lib/api/generated"; / シリーズ下書き一覧を取得するカスタムフック SWRのキャッシュ・再検証・データ共有の恩恵を受けられる / export const useSeriesDraftsControllerFindAll = () => { return useSWR("/api/series-drafts", () => seriesDraftsControllerFindAll()); }; // コンポーネントでの使用 const { data, error, isLoading } = useSeriesDraftsControllerFindAll(); SWRのキャッシュ戦略により、複数のコンポーネントで同じデータを効率的に共有できます。フォーカス時の自動再検証なども自動で行われるので、常に新鮮なデータを表示できるんですよね。 パターン2: mutation(直接Axios呼び出し) 一方、データの作成・更新・削除は直接Axiosを呼び出します。 import { useState } from "react"; import { mutate } from "swr"; import { seriesDraftsControllerCreate } from "@/lib/api/generated"; const [isCreating, setIsCreating] = useState(false); / シリーズ下書きを作成する処理 SWRのオーバーヘッドなしで、シンプルに実装できる / const handleCreate = async (data) => { setIsCreating(true); try { await seriesDraftsControllerCreate(data); // 作成後、SWRキャッシュを更新して一覧を再取得 mutate("/api/series-drafts"); } finally { setIsCreating(false); } }; このアプローチなら、不要なオーバーヘッドを回避できて、フォーム状態との統合も容易になります。必要に応じて mutate() でSWRキャッシュを更新すれば、一覧表示も自動的に最新化されます。 シンプルでわかりやすいですよね。 移行中に発見したバグ 実は移行作業中に、思わぬバグも見つかりました。 axiosInstance と axiosClient の混同 : 3つのファイルで axiosClient をAxiosインスタンスとして誤使用していたんです。 // ❌ Before(バグ) import { axiosClient } from "@/lib/axiosClient"; await axiosClient.get("/.auth/me"); // TypeError! // ✅ After(修正) import { axiosInstance } from "@/lib/axiosClient"; await axiosInstance.get("/.auth/me"); 教訓 : axiosClient はOrval mutator関数として使うもので、直接HTTP呼び出しには axiosInstance を使用する必要があります。 命名が似ていると、こういう混同が起きやすいんですよね。移行作業のおかげで、潜在的なバグを早期発見できたのは副次的な効果でした。 移行結果:数字で見る効果 実際の移行結果をまとめてみます。 対象範囲と効果 47ファイル移行完了 (実装時間: 4.2時間、推定14-20時間 → 21-30%効率化) バンドルサイズ20-30%削減 (自動生成フック: 41個 → 0個) カスタムフック : 9個を必要箇所のみ作成 コード行数 : ~2030行 → ~800行(約60%削減) 当初は14-20時間かかると見積もっていたんですが、4.2時間で完了できました。Axiosの関数がパーツとして提供されていたおかげで、AIに実装を任せる際もスムーズに進められたんです。 AI開発を効率化する「パーツ提供」の考え方 今回の経験で実感したのが、 AI開発を効率化する鍵は「パーツを提供する」という考え方 だということです。 shadcn/uiが成功しているのも同じ理由ではないでしょうか。コンポーネントをコピペして、必要に応じてカスタマイズできる。全部を自動生成するのではなく、パーツを提供する。 Axiosのインターフェース部分をパーツとして切り出しておけば、そこに処理を書かせるだけでOK。このアプローチによって、開発効率が飛躍的に向上しました。 フロントエンドとバックエンドの型の齟齬もなくなりましたし、手が止まることも減りました。すっきりとしたコードで実装できるようになったんです。 まとめ:適材適所が長期的な保守性を生む SWRは素晴らしいツールです。でも、すべてのAPI呼び出しに必要なわけではありません。 適材適所のアプローチ : データ取得(Read) : SWRの恩恵を最大限活用 mutation(CUD) : シンプルにAxiosで十分 「便利だから」という理由で全てを自動生成すると、不要な複雑さとバンドル肥大化を招いてしまいます。 Axiosでパーツのみを提供し、SWRは必要な箇所に手動で適用する。この「適材適所」のアプローチが、長期的な保守性と柔軟性を生むんですね。 皆さんも、もし自動生成で「何か複雑になってきたな」と感じたら、一度立ち止まって考えてみてください。本質的に必要なものは何か、ツールの設計思想に沿った使い方ができているか。そこを見直すことで、より良い設計にたどり着けるはずです。 今回の知識を活かして、ぜひ皆さんのプロジェクトでも最適なアプローチを見つけてみてください! 参考リソース Orval – OpenAPI to TypeScript SWR – React Hooks for Data Fetching 包括的な実装検証ドキュメント ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Orval SWRの自動生成をやめた理由 – SWRの本質を見失っていた話 first appeared on SIOS Tech. Lab .
こんな方へ特におすすめ これから本格的なWebアプリ開発を始めたい方 自分だけの快適な開発環境を整えたい方 チーム開発で「自分の環境だけ動かない…」を撲滅したい方 PCを買い替えてもすぐに開発を再開したい方 概要 こんにちは。サイオステクノロジーのはらちゃんです!今回5本目のブログ執筆です。 今回は、バックエンド(Python/FastAPI)とフロントエンド(Node.js/React)を分離したモダンなWebアプリケーション開発を想定し、 VS CodeのDev Container 機能を使って、誰でも同じ環境を再現できる開発環境を構築する手順を解説します。 Dev Containerという最適解 新しいプロジェクトを始めるたびに 「Pythonのバージョンは…?」 「Node.jsのバージョンは…?」 と環境構築で時間を取られていませんか?Dev Containerは、Dockerコンテナーの技術を使い、プロジェクトごとに隔離された最適な開発環境をコード(設定ファイル)で管理できるVS Codeの素晴らしい機能です。 これを使えば、新しいメンバーも数コマンドであなたと全く同じ開発環境を立ち上げることができます。今回は、無料のAIコーディング支援ツール Codeium も導入し、より快適な環境を目指します。 発生しがちなエラーとその解決策も詳しく紹介するので、ぜひ最後までお付き合いください! Step0:前提条件 VSCodeがインストールされている Docker Desktopまたは Rancher Desktop がインストールされている (Windowsの場合) WSL2が有効になっている Step1:プロジェクトの骨格を作る まず、プロジェクト全体のフォルダ構成を整え、Dockerで各サービス(バックエンド、フロントエンド、DB)をどう連携させるかを定義する docker-compose.yml を作成します。 ディレクトリの作成 以下のようなフォルダ構成を作成します。 .devcontainer フォルダの中に backend と frontend のサブフォルダを作るのがポイントです。 HaraSpace/ │ ├── .devcontainer/ │ │ │ ├── backend/ │ │ └── devcontainer.json │ │ │ └── frontend/ │ └── devcontainer.json │ ├── backend/ │ │ │ ├── Dockerfile │ └── requirements.txt │ ├── frontend/ │ │ │ ├── Dockerfile │ └── package.json │ ├── docker-compose.yml │ └── wait-for-it.sh docker-compose.ymlの作成 プロジェクトのルートに、3つのサービスを定義する docker-compose.yml を作成します。 docker-compose.yml services: backend: build: context: . dockerfile: backend/Dockerfile target: development # 開発用ステージを指定 command: ["wait-for-it.sh", "db:3306", "--", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] volumes: - ./backend:/workspace/backend ports: - "8000:8000" depends_on: - db frontend: build: context: . dockerfile: frontend/Dockerfile target: development # 開発用ステージを指定 # --hostフラグでコンテナ外からのアクセスを許可 command: ["npm", "run", "dev", "--", "--host"] volumes: - ./frontend:/workspace/frontend ports: - "3001:3000" depends_on: - backend db: image: mysql:8.0 ports: - "3307:3306" environment: - MYSQL_ROOT_PASSWORD=your_root_password - MYSQL_DATABASE=sql_app_db volumes: - db_data:/var/lib/mysql volumes: db_data: wait-for-it.sh ファイルの準備 GitHub からダウンロードし、プロジェクトの ルートディレクトリ ( docker-compose.yml と同じ場所)に配置するのが一般的です。 Step2:各サービスの設計図を書く 次に、バックエンドとフロントエンドそれぞれのコンテナー環境の設計図となる Dockerfile を作成します。今回は、開発用と本番用で設定を分ける「 多段ビルド 」という手法を採用します。 バックエンド 現在の既定である、Python 3.12をベースイメージとして使用します。 backend/Dockerfile # ---- 1. 全ステージで共通のベース ---- FROM python:3.12-slim as base WORKDIR /workspace/backend ENV PYTHONPATH "${PYTHONPATH}:/workspace/backend" # wait-for-it.shをコピーして実行権限を付与 COPY wait-for-it.sh /usr/local/bin/wait-for-it.sh RUN chmod +x /usr/local/bin/wait-for-it.sh # 依存関係をインストール COPY backend/requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt # ---- 2. 開発用ステージ ---- FROM base as development CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] # ---- 3. 本番用ステージ ---- FROM base as production # (ここに本番用の設定を記述...) 同じディレクトリに必要なライブラリを記述します。 backend/requirements.txt fastapi uvicorn[standard] pymysql フロントエンド Node.js 22をベースに使います。VS Codeとの相性を考慮し、 alpine ではなく slim イメージを使うのが安定動作の鍵です。 frontend/Dockerfile # ---- 1. ベースステージ (依存関係のインストール) ---- FROM node:22-slim as base WORKDIR /workspace/frontend COPY frontend/package*.json ./ RUN npm ci # ---- 2. 開発用ステージ ---- FROM base as development COPY frontend/ ./ EXPOSE 3000 CMD ["npm", "run", "dev", "--", "--host"] # ---- 3. 本番用ステージ ---- FROM base as production # (ここに本番用の設定を記述...) フロントエンドも同じディレクトリに必要なライブラリを記述します。 手動で package.json を作成するよりも、 Vite (ヴィート) というツールを使ってプロジェクトの雛形を自動生成するのが現在の主流で、簡単かつ確実です。 frontend ディレクトリの中で以下のコマンドを一度実行するだけで、ReactやVueなどに最適化された最低限の package.json が自動的に作成されます。 まず、 frontend ディレクトリに移動します。 bash cd frontend 次に、Viteの作成コマンドを実行します。 bash npm create vite@latest . -- --template react このコマンドを実行すると、いくつかの質問をされますが、基本的にはEnterキーを押していけばOKです。 Step 3:VS Codeとコンテナーを繋ぐ設定 最後に、VS Codeに対して「どちらのコンテナーに接続して開発作業を行うか」を教えるための devcontainer.json を作成します。 バックエンド backend/Dockerfile { "name": "Backend Container", // 使用するdocker-compose.ymlのパスを、このファイルからの相対パスで指定 "dockerComposeFile": [ "../../docker-compose.yml" ], // docker-compose.ymlに定義したサービスの中から、接続したいサービス名を指定(最重要) "service": "backend", // コンテナに接続したときに開く作業フォルダ "workspaceFolder": "/workspace/backend", "customizations": { "vscode": { // Python開発に特化した拡張機能を追加 "extensions": [ "ms-python.python", "ms-python.vscode-pylance", "charliermarsh.ruff" // Python用の高速Linter ] } } } フロントエンド frontend/Dockerfile { "name": "Frontend Container", // 使用するdocker-compose.ymlのパス "dockerComposeFile": [ "../../docker-compose.yml" ], // 今度は'frontend'サービスに接続するよう指定 "service": "frontend", // フロントエンド用の作業フォルダを指定 "workspaceFolder": "/workspace/frontend", "customizations": { "vscode": { // フロントエンド開発に特化した拡張機能を追加 "extensions": [ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "Codeium.codeium" ] } }, // フロントエンドのポートをフォワーディング "forwardPorts": [3001] } これで準備完了です!VS Codeでプロジェクトフォルダを開き、左下の緑色のアイコン >< をクリックして「 コンテナーで再度開く (Reopen in Container) 」を選択すると、バックエンドとフロントエンドのどちらで作業を開始するか選べるようになります! ハマりどころを徹底解説!よくあるエラーと解決策 環境構築にはエラーがつきものです。今回私が遭遇した主なエラーとその解決策を共有します。 エラー1: wait-for-it.sh: not found や Dockerfile の変更が反映されない 原因 Dockerが古いイメージキャッシュを使い回している可能性があります。 対処法 VS Codeのコマンドパレット( Ctrl+Shift+P or Cmd+Shift+P )から Dev Containers: Rebuild and Reopen in Container を実行し、イメージを強制的に再構築します。 エラー2: port is already allocated (ポートが既に使用されている) 原因 以前のコンテナーが完全に停止しておらず、ポートを掴んだままになっています。 対処法 プロジェクトルートでターミナルを開き、 docker compose down コマンドを実行して関連コンテナーをすべて停止・削除します。 エラー3: Exit code 137 (メモリ不足) 原因 Docker (特にRancher Desktop) に割り当てられたメモリが不足し、コンテナーがOSに強制終了させられています。 対処法 (Rancher Desktopの場合) : Windowsのユーザーフォルダ( C:\Users\<ユーザー名> )に .wslconfig というファイルを作成します。 以下の内容を記述して保存します。(PCの搭載メモリに合わせて 8GB の部分を調整) PowerShellで wsl --shutdown を実行し、Rancher Desktopを再起動して設定を反映させます。 PowerShell notepad .wslconfig もしファイルがまだ存在しない場合、「 新しいファイルを作成しますか? 」と聞かれるので、「 はい 」をクリックしてください。メモ帳が起動します。 開いたメモ帳に、以下の内容をコピーして貼り付けてください。 [wsl2] memory=8GB processors=4 memory=8GB : WSL全体で使用できるメモリの上限を8GBに設定します。PCの搭載メモリの半分程度を目安に、 6GB や 12GB などに調整してください。 この設定が最も重要です。 processors=4 : WSLが使用できるCPUコア数を4に設定します。PCのCPU性能に合わせて調整すると、より快適になります(省略しても構いません)。 この設定を有効にするには、WSLを 完全にシャットダウン する必要があります。 PowerShellのウィンドウに戻り、以下のコマンドを打ち込んでEnterキーを押してください。 PowerShell wsl --shutdown コラム:Codeiumとは… Codeiumは、AIを活用してコーディングを支援するツールです。 無料で始められる 手軽さと 強力なコード補完機能 で、GitHub Copilotの代替としても注目されています。 AIによるコード自動補完 入力中のコードの続きを予測して、関数全体や定型文などを数行にわたって提案してくれます。 AIとのチャット エディタ内でAIチャットが利用できます。コードの解説、リファクタリング、テストコードの生成、デバッグの補助など、コーディングに関する様々な質問や依頼を自然言語で行えます。 70以上の言語に対応 PythonやJavaScriptといった主要な言語はもちろん、C++、Java、Goなど、70種類以上のプログラミング言語に対応しており、幅広い開発プロジェクトで利用できます。 多くのエディタに対応 Visual Studio Codeをはじめ、JetBrains製IDE(IntelliJ IDEA, PyCharmなど)、Vim/Neovim、Jupyter Notebookなど、普段使っている開発環境に拡張機能として簡単に追加できます。 プライバシーとセキュリティ Codeiumは、ユーザーのコードをAIの学習データとして保存しない仕組みを採用しています。そのため、企業の機密情報や個人のプロジェクトでも安心して利用できます。 まとめ お疲れ様でした!今回は、バックエンドとフロントエンドを柔軟に切り替えながら開発できる、再現性の高いDev Container環境が完成しました。 最初は設定ファイルが多くて戸惑うかもしれませんが、一度この環境を構築してしまえば、あとは 設定ファイルをGitで管理するだけ で、チームメンバー全員が数分で全く同じ開発環境を手に入れることができます。 Github に今回紹介した開発構成をプッシュしているのでそちらもご活用ください。 環境差異による不毛なトラブルから解放され、本来集中すべきアプリケーション開発に時間を使えるようになります。ぜひDev ContainerとCodeiumを活用して、快適な開発ライフを送ってください! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 1人がこの投稿は役に立ったと言っています。 The post 開発環境の作り方|Dev ContainerとCodeiumの活用 first appeared on SIOS Tech. Lab .
こんにちは、伊藤です。 Microsoft Entra IDでは、CSVファイルによるアカウント作成、削除の一括処理機能がありますが、パスワードの一括リセット機能はありません。 また、管理者がMicrosoft Entra IDのパスワードをリセットする場合、一般的には以下のようにユーザーの概要ページから実行します。しかし、この方法では任意のパスワードを指定できません(オンプレミスADとのアカウント同期とパスワードの書き戻しが有効な場合を除く)。 そこで今回は、これらの課題を解決するため、CSVファイルを使ってMicrosoft Entra IDのユーザーパスワードを一括でリセットするPowerShellスクリプトと、その使い方を紹介します。 本稿で取り上げた課題およびコードは2025年10月段階のものであり、今後のMicrosoft Entra IDの更新により解決されたり、修正が必要になったりする場合があります。 前提条件 ・Microsoft Entra IDテナントと、そのユーザーに対してパスワードリセットを実行できる管理者アカウントを保有していること ・使用するPowerShellにMicrosoft Graph PowerShell SDKがインストールされていること 以下のコマンドでMicrosoft Graph PowerShell SDKをインストールできます。 Install-Module Microsoft.Graph.Users -Scope CurrentUser パスワードリセット用CSVファイルを作成する 一括パスワードリセット用のCSVファイルを作成します。 ユーザープリンシパル名(UserPrincipalName)、パスワード(Password)の列を指定します。 パスワードを指定しない場合は、スクリプトがランダムなパスワードを生成します。 例: UserPrincipalName,Password test01@example.com,P@ssw0rd test02@example.com, PowerShellスクリプトを作成する PowerShellスクリプトファイルを作成します。 -InputFile オプションでCSVファイルを指定し、 -OutputFile オプションで一括パスワードリセット結果のファイルを指定できるようにします。 -OutputFile を指定しない場合は、タイムスタンプ付きのファイルが作成されます。例: reset_results_20250829155001.csv CSVファイルでパスワードを指定したユーザーはそのパスワードに、指定しなかったユーザーはランダムに生成されたパスワードにリセットされます。ランダムパスワードは、英大文字、英小文字、数字、記号がそれぞれ2文字以上含まれる16文字のランダム値を生成します。 ・entraidpasswordreset.ps1 #requires -Modules Microsoft.Graph.Users param( [Parameter(Mandatory = $true, HelpMessage = "ユーザーリストのCSVファイルパスを指定してください")] [string]$InputFile, [Parameter(HelpMessage = "結果を出力するCSVファイルパスを指定してください")] [string]$OutputFile = ".\reset_results_$(Get-Date -Format 'yyyyMMddHHmmss').csv" ) # Microsoft Graphに接続します (未接続の場合) if (-not (Get-MgContext)) { Write-Host "Microsoft Graphに接続します..." -ForegroundColor Yellow # 必要なアクセス許可スコープを指定して接続 Connect-MgGraph -Scopes "User-PasswordProfile.ReadWrite.All" } # 結果を格納するための空の配列を作成 $results = @() # CSVファイルからユーザーリストをインポート try { $users = Import-Csv -Path $InputFile } catch { Write-Host "エラー: 入力ファイルが見つからないか、読み込めません。パスを確認してください: $InputFile" -ForegroundColor Red return } Write-Host "パスワードリセット処理を開始します..." -ForegroundColor Cyan # 各ユーザーに対してループ処理 foreach ($user in $users) { $upn = $user.UserPrincipalName $newPassword = $null $forceChangeOnNextSignIn = $true # 次回サインイン時にパスワード変更を強制 try { # CSVにPassword列が存在し、かつ値が空でないかチェック if ($user.PSObject.Properties.Match('Password') -and -not [string]::IsNullOrEmpty($user.Password)) { # --- パターン1: CSVで指定されたパスワードを使用 --- $newPassword = $user.Password Write-Host "[$upn] CSVで指定されたパスワードを設定します。" } else { # --- パターン2: ランダムなパスワードを生成 --- Write-Host "[$upn] ランダムパスワードを生成します。" $charSets = @{ Upper = 'ABCDEFGHIJKLMNPQRSTUVWXYZ' Lower = 'abcdefghijlkmnpqrstuvwxyz' Number = '0123456789' Symbol = '@#$%^&*-_!+=[]{}|\:'',.?/`~"();<>' } $passwordChars = [char[]]($charSets.Upper.ToCharArray() | Get-Random -Count 2) + [char[]]($charSets.Lower.ToCharArray() | Get-Random -Count 2) + [char[]]($charSets.Number.ToCharArray() | Get-Random -Count 2) + [char[]]($charSets.Symbol.ToCharArray() | Get-Random -Count 2) $remainingChars = [char[]]($charSets.Values -join '') | Get-Random -Count 8 $newPassword = ($passwordChars + $remainingChars | Get-Random -Count 16) -join '' } # パスワードリセットの実行 $passwordProfile = @{ ForceChangePasswordNextSignIn = $forceChangeOnNextSignIn Password = $newPassword } Update-MgUser -UserId $upn -PasswordProfile $passwordProfile -ErrorAction Stop Write-Host "成功: $($upn) のパスワードをリセットしました。" -ForegroundColor Green $results += [PSCustomObject]@{ UserPrincipalName = $upn NewPassword = $newPassword Status = "Success" } } catch { $errorMessage = $_.Exception.Message Write-Host "失敗: $($upn) のパスワードリセット中にエラーが発生しました。エラー: $errorMessage" -ForegroundColor Red $results += [PSCustomObject]@{ UserPrincipalName = $upn NewPassword = "N/A" Status = "Failed - $errorMessage" } } } # 結果をCSVファイルに出力 $results | Export-Csv -Path $OutputFile -NoTypeInformation -Encoding UTF8 # Microsoft Graphから切断します Write-Host "Microsoft Graphから切断します..." -ForegroundColor Yellow Disconnect-MgGraph Write-Host "全ての処理が完了しました。結果は '$($OutputFile)' を確認してください。" -ForegroundColor Cyan このスクリプトは、ユーザーが次回サインインする際にパスワードの変更を強制します。 もしパスワード変更を強制したくない場合は、スクリプト内の以下の行を見つけ、値を $true から $false に修正してください。 変更前: $forceChangeOnNextSignIn = $true # 次回サインイン時にパスワード変更を強制 変更後: $forceChangeOnNextSignIn = $false # 次回サインイン時にパスワード変更を強制しない PowerShellスクリプトを実行してユーザーパスワードを一括リセットする PowerShellスクリプトを実行します。 例: > .\entraidpasswordreset.ps1 -InputFile .\reset_users.csv -OutputFile .\reset_users_result.csv Microsoft Graphに未接続の場合はログイン画面が表示されます。Microsoft Entra IDのユーザーに対してパスワードリセットを実行できる管理者アカウントでログインします。 Microsoft Graphに接続後はパスワードリセット処理が実行されます。 パスワードリセットに成功した場合は「成功: <ユーザープリンシパル名>のパスワードをリセットしました。」と表示されます。 パスワードリセットに失敗した場合は「失敗: <ユーザープリンシパル名>のパスワードリセット中にエラーが発生しました。」と表示されます。 全ての処理が完了すると、一括パスワードリセット結果が出力用のCSVファイルに書き込まれます。このファイルには、ユーザープリンシパル名、新しいパスワード、そして処理結果(成功の場合は「Success」、失敗の場合は「Failed – <エラーの詳細>」)が記録されます。 例: "UserPrincipalName","NewPassword","Status" "pwreset-test01@example.com","deko89IFLEU","Success" "pwreset-test02@example.com","H7T*#t9smrahS@3U","Success" "pwreset-test03@example.com","N/A","Failed - [Request_BadRequest] : The specified password does not comply with password complexity requirements. Please provide a different password." パスワードリセットの失敗例 パスワードリセットに失敗した場合のよくある原因を以下に示します。 Microsoft Graphに接続できない Microsoft Graphに接続できなかった場合は以下のエラー文が表示されます。 Authentication needed. Please call Connect-MgGraph. ユーザーがMicrosoft Entra IDテナント内に存在しない Microsoft Entra IDテナント内に存在しないユーザープリンシパル名を指定すると、対象ユーザーが存在しないためエラーになります。この場合は以下のエラー文が表示されます。 [Request_ResourceNotFound] : Resource '<指定したユーザープリンシパル名>' does not exist or one of its queried reference-property objects are not present. リセットしようとしたパスワードが、Microsoft Entra IDのパスワードポリシーに違反している パスワードを指定してリセットした場合、Microsoft Entra IDのパスワードポリシーによりパスワードのリセットに失敗する場合があります。この場合は以下のエラー文が表示されます。 [Request_BadRequest] : The specified password does not comply with password complexity requirements. Please provide a different password. パスワードポリシーを無視してパスワードをリセットしたい場合は、ユーザーのパスワードポリシーを一時的に変更してパスワードをリセットすることも可能です。その場合は、Microsoft Graphに接続する箇所およびユーザー情報を更新する箇所を修正してください。 <省略> # Microsoft Graphに接続します (未接続の場合) if (-not (Get-MgContext)) { Write-Host "Microsoft Graphに接続します..." -ForegroundColor Yellow # 必要なアクセス許可スコープを指定して接続 Connect-MgGraph -Scopes "User.ReadWrite.All,User-PasswordProfile.ReadWrite.All" } <省略> # パスワードリセットの実行 $passwordProfile = @{ ForceChangePasswordNextSignIn = $forceChangeOnNextSignIn Password = $newPassword } Update-MgUser -UserId $upn -PasswordPolicies "DisableStrongPassword" -ErrorAction Stop Update-MgUser -UserId $upn -PasswordProfile $passwordProfile -ErrorAction Stop Update-MgUser -UserId $upn -PasswordPolicies None -ErrorAction Stop <省略> Microsoft Entra IDの運用上パスワードを無期限にしたい場合は、パスワードリセット処理後のパスワードポリシー( -PasswordPolicies )を None から "DisablePasswordExpiration" に修正してください。 まとめ 今回は、CSVファイルを利用してMicrosoft Entra IDのユーザーパスワードを一括リセットするPowerShellスクリプトを紹介しました。 Microsoft Entra IDのアカウント管理に活用していただけると幸いです。 参考 参考 Microsoft Graph PowerShell を使用してパスワードを管理する – Microsoft 365 Enterprise 参考 セルフサービス パスワード リセット ポリシー – Microsoft Entra ID 参考 PowerShell を使用してランダムな文字列を生成する方法 Delft スタック ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Microsoft Entra IDのユーザーパスワードを一括リセットする first appeared on SIOS Tech. Lab .
はじめに 今回から複数の記事にまたがって KubernetesでDBを管理するために役立つKubeBlocksというソリューションについて解説します。KubeBlocksがどんなソリューションであるか理解するとともにKubernetesでのDB管理の重要性について理解していただけると幸いです。 DBaaSとは Kubeblocksの解説に入る前に、まず「DBaaS」と、それをKubernetes上で実現するメリットについて整理します。 DBaaS(Database as a Service)とは、クラウド上で提供されるデータベース管理サービスです。 従来のデータベース管理はデータベースサーバーのセットアップからパッチ適用、バックアップ、監視といった運用タスクを手動で行う必要がありました。DBaaSを利用することで、それらの操作を簡易化・自動化することが可能になります。 従来のDB管理とDBaaSの比較 KubernetesでDB管理することの重要性 DBをKubernetesで管理することによって大きく3つの利点があります。 運用プラットフォームの統一 Kubernetesにアプリケーションをデプロイして、外部でDBを管理している場合、運用するプラットフォームが分断されて運用コストが上がってしまいます。アプリケーションがデプロイされているKubernetes上でもDBを管理することで運用がシンプルになり、運用コストを抑えることができます。 高度なDB構成を簡易に構築 Kubernetesのオーケストレーション機能を活用することで、冗長性や可用性を考慮した高度なDB構成を簡易に構築することが可能です。 また、DBの運用作業を自動化することが可能で、構築から運用まですべての管理を効率化することができます ベンダーロックインの回避 特定のクラウドベンダーのDBaaSを利用すると、その特定のシステムの仕様に深く依存することになり、将来的に別の環境に移行する際の障壁が高くなります。 KubernetesでDB管理する場合、YAMLファイルといった統一的なファイルを利用することで別環境でも同一のDB構成を簡単に構築することが可能です。 KubeBlocksの概要 KubeBlocksはデータベース用のオープンソースKubernetesオペレーターです。 KubeBlocksの構造(参照:https://kubeblocks.io/docs/preview/user_docs/overview/introduction) KubeBlocksを導入することによってKubernetesクラスタ上に、DBaaSを構築することが可能です。 KubeBlocksの大きな特徴として、特定のDBに依存しない汎用的なDBオペレーターになっています。これにより、データベースのデプロイ、スケーリング、バックアップといった複雑な運用タスクが自動化されます。さらに、PostgreSQLやMySQLなど様々な種類のデータベースを、統一されたYAML記法で管理できるため、複数DBの運用が非常にシンプルかつ効率的になります。   MySQLクラスターを構築するYAMLファイルの例 apiVersion: apps.kubeblocks.io/v1 kind: Cluster metadata: name: test-mysql namespace: demo spec: terminationPolicy: Delete componentSpecs: - name: mysql componentDef: "mysql-8.0" serviceVersion: 8 . 0 . 35 disableExporter: false replicas:   2 resources: limits: cpu: '0.5' memory: 0 . 5Gi requests: cpu: '0.5' memory: 0 . 5Gi volumeClaimTemplates: - name: data spec: storageClassName: "" accessModes: - ReadWriteOnce resources: requests: storage: 20Gi PostgreSQLクラスターを構築するYAMLファイルの例 apiVersion: apps.kubeblocks.io/v1 kind: Cluster metadata: name: test-pg namespace: demo spec: terminationPolicy: Delete clusterDef: postgresql topology: replication componentSpecs: - name: postgresql serviceVersion: 16.4.0 disableExporter: true replicas: 2 resources: limits: cpu: "0.5" memory: "0.5Gi" requests: cpu: "0.5" memory: "0.5Gi" volumeClaimTemplates: - name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi KubeBlocksには「kbcli」というコマンドラインツールが備わっています。これを利用することでKubeBlocksのリソースの操作をより簡単に行うことが可能です。 「kbcli」で出来る操作としてDBクラスタのバックアップの作成、kbcliの追加機能の管理、データベースクラスタのライフサイクル管理、kubeBlocks自体の管理などがあります。 KubeBlocksに対応しているDBソリューションに関してはシリーズ第2回となる次のブログ記事で、具体的な一覧と共に詳しく解説します。 KubeBlocksでDBクラスターを構築した際の構成例が以下になります: KubeBlocksの構成例(参照:https://kubeblocks.io/docs/preview/user_docs/overview/introductio) デフォルトでは、KubeBlocks Control Planeと呼ばれるKubeBlokcsの管理を行うノードとKubeBlocks Data Planeと呼ばれるDBがデプロイされるノードに別れます。これにより高可用性を保持することが可能になります。 さらに、データベースクラスターの各レプリカをAvailability Zones(AZ)に分散させることで、災害復旧能力も高めることが可能です。 KubeBlocksの主要機能 様々な種類のDBクラスターのプロビジョニング・削除・起動・停止・再起動 幅広いDay-2 オペレーション 水平スケーリング 垂直スケーリング DBクラスターが使用しているPVCの拡張 バックアップ・リストア DB構成の変更 DBインスタンスの移行 ローリングアップデート Prometheusと連携した監視 他類似OSSDB管理ソリューションとの比較 Kubernetes上でデータベースを管理するためのオペレーターはいくつか存在しますが、ここでは代表的なオープンソースのオペレーターであるKubeDB, Percona Everest, StackGresとKubeBlocksを比較し、それぞれ特徴と最適なユースケースを探ります。 OSSDB管理ソリューションの比較 この比較表から分かるように、各オペレーターには得意分野があります。 KubeDB KubeDBは、非常に多くのデータベースをサポートする汎用性の高いオペレーターです 。運用機能も豊富で、GitOpsとの連携も可能です 。ただし、オープンコアモデルを採用しており、バックアップや監視などの多くの高度な機能は有償のエンタープライズ版でのみ利用可能という点に注意が必要です 。 Percona Everest Percona Everestは、Perconaが提供するデータベース(PostgreSQL, MySQL, MongoDB)に特化しています 。最大の特徴は、Perconaの強力な監視ツール「PMM (Percona Monitoring and Management)」と深く連携し、クエリ分析など高度な監視を容易に実現できる点です 。直感的なWeb UIも提供されており、CLI操作に不慣れなユーザーでも扱いやすいのが魅力です 。 StackGres StackGresは、対応データベースをPostgreSQLに絞ることで、その運用を極限まで自動化・最適化することに特化したオペレーターです 。高可用性を実現するPatroniや接続プーリングを行うPgBouncerが標準で統合されており、150以上の拡張機能が利用可能です 。PostgreSQLをメインで利用する開発チームにとって、最も高機能な選択肢の一つと言えるでしょう。100%オープンソースであることも大きな特徴です 。 おわりに 本記事では、Kubernetes上でDBaaSを実現するソリューションとして、オープンソースの汎用データベースオペレーター「KubeBlocks」を解説しました。KubeBlocksは、特定のデータベースに依存しない高い汎用性を持ち、多種多様なデータベースを統一された手法で効率的に管理できる非常に強力なツールです。 多様なデータベースを運用している環境 運用をシンプルに統一したいチーム 上記のようなニーズを持つチームにとって、KubeBlocksは最適な選択肢の一つとなるでしょう。今後もKubeBlocksについての解説ブログを掲載していくのでよろしくお願いします。 参考文献 KubeBlocks公式ドキュメント: https://kubeblocks.io/docs/preview/user_docs/overview/introduction KubeDB公式ドキュメント: https://kubedb.com/ Percona Everest公式ドキュメント: https://www.percona.com/software/percona-everest StackGres公式ドキュメント: https://stackgres.io/features/ kbcliコマンドリファレンス: https://kubeblocks.io/docs/preview/cli/kbcli ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post KubeBlocksとは?KubernetesでDBを管理する新常識 first appeared on SIOS Tech. Lab .
OSS よろずチームの神﨑です。 RHEL 10 同梱版の Podman の変更点について簡単にまとめていきたいと思います。 Podman のインストールと起動確認 AWS の RHEL10 のインスタンスで検証しています。 1.インストール # dnf install podman # podman version Client: Podman Engine Version: 5.4.0 API Version: 5.4.0 Go Version: go1.23.10 (Red Hat 1.23.10-1.el10_0) Built: Wed Jun 25 00:00:00 2025 Build Origin: Red Hat, Inc. <http://bugzilla.redhat.com/bugzilla> OS/Arch: linux/amd64 2.コンテナイメージ導入 (httpd) # podman search httpd # podman pull registry.access.redhat.io/ubi10/httpd-24 3. コンテナの起動 実行例 # podman run -d -p 8080:8080/tcp --name my-rootless-httpd registry.redhat.io/ubi10/httpd-24 Podman に関する変更点 RHEL 公式ドキュメントを確認したところ以下の記述がありました。 containers.conf ファイルの読み取り専用となる システム接続とファームの情報が containers.connections.json に移動しました。 CNI ネットワークスタックのサポート終了と netavark への移行 containernetworking-plugins パッケージが削除され、CNI がサポートされなくなります。 runc コンテナランタイムの削除 デフォルトのコンテナランタイムが crun になります。 slirp4netns ネットワークモードが非推奨となる ルートレスコンテナのデフォルトネットワークモードが pasta になります。 RHEL 10 ホストでの RHEL 7 コンテナの非サポート 詳細は、 Red Hat Enterprise Linux Container Compatibility Matrix  を参照してください。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post RHEL 10 同梱版の Podman についての調査 first appeared on SIOS Tech. Lab .
Webサイトやアプリ開発の現場で、「デザインシステム」という言葉を耳にする機会が増えていませんか?「なんだか難しそう…」「自分には関係ないかも」と感じている方もいるかもしれません。 しかし、デザインシステムは、開発の効率を上げ、チームのコミュニケーションを円滑にし、プロダクトの品質を一貫して高く保つための、非常に強力な武器になります。 この記事で「良さそう、面白そう」と思っていただければ幸いです。 デザインシステムとは? 「デザインシステム」って、そもそも何でしょうか? その定義は場合によって異なり、ひとつに定めるのは、難しいです。 そこで、ザックリ「狭義の…」「広義の…」と2つに分けて解釈を試みます。 狭義のデザインシステム:再利用可能な「部品集」 狭義のデザインシステムは、 デザインの具体的な構成要素やルールをまとめたもの を指します。これは、デザイナーやエンジニアが直接的に利用する「部品」や「説明書」の集まりと考えると分かりやすいでしょう。 UIコンポーネント : ボタン、フォーム、アイコン、カードなど、繰り返し使えるデザインの部品。 デザイントークン : 色、タイポグラフィ(フォントサイズや種類)、スペーシング(間隔)などを管理する変数。これにより、デザインの変更が一括で容易になります。 スタイルガイド : ブランドのロゴの使用法や、デザインの原則などを定めたルールブック。 ドキュメンテーション : 各コンポーネントの使い方や、デザインの意図を解説した文書。 これらは、Figmaのようなデザインツールや、Storybookのような開発者向けのコンポーネントライブラリとして具体的に存在します。 一言でいうと :「デザインと開発で使う、再利用可能な『レゴブロック』と『その組み立て方』のセット」です。 広義のデザインシステム:一貫性を生み出す「文化」と「プロセス」 広義のデザインシステムは、単なる部品集にとどまらず、 製品開発に関わる人々の協力体制や思想、ワークフロー全体 を包含します。 思想と原則 : なぜそのデザインなのか?という根本的な考え方や、チームが共有する価値観(例:「シンプルであること」「アクセシビリティを重視すること」など)。 コミュニケーション : デザイナー、エンジニア、プロダクトマネージャーなどが円滑に協力するためのコミュニケーションの仕組みや文化。 ガバナンス : デザインシステムを誰が、どのように更新し、管理していくかという運用ルール。 ワークフロー : デザインシステムを実際の製品開発に組み込み、継続的に改善していくプロセス。 こちらは、ツールとして存在するだけでなく、チームの文化や働き方そのものに根付いています。 一言でいうと :「良い製品を効率的に作り続けるための『共通言語』であり、チームの『文化』」です。 上記はあえて2つに分類しましたが、実際のデザインシステムは広義と狭義の中間にあることが多いかと思います。 また、デザインシステムは、一度作って終わりではありません。プロダクトやチームの成長に合わせて、継続的に育てていくものです。 なぜ、いま「デザインシステム」なのか? 「車輪の再発明」を減らす パソコンとスマートフォンは、多くのひとの仕事や生活のツールとして実用化し、コモディティ化と言ってよい段階と捉えています。 わたしたちが、新たなアプリケーション、ウェブサイトを構築する際、多くの場合に既存のデザインシステムが参考になります。 SmartHRのデザインシステムにて述べられている「“車輪の再発明”を減らす」という考え方です。 https://smarthr.design/introduction/operate-policy 巨人の肩の上に立つ ありがたいことに、世界の大企業や政府を始めとする、さまざまな団体の知見を活用することができます。 公開された各デザインシステムは、日々進化していますが、その多くが高い品質に達しています。 生成AI時代のUIの土台 「生成AI」によって、コンピューターを利用するためのインターフェースは、見直されていくかもしれません。 今後、AIによってUIの生成が自動化されても、その基盤となる一貫したルールやコンポーネントは必要となるでしょう。 事例紹介:世界の優れた公開デザインシステム 品質、汎用性、応用性が高く、Figmaファイルも公開されているデザインシステムを、UIデザイナーの視点でピックアップして、紹介します。 政府系 行政は対象者が多様なため、特にアクセシビリティを重視していることが特徴かと思います。 文字やボタンなどの要素は大きく、余白も十分。 イギリス政府「GOV.UK Design System」 https://design-system.service.gov.uk/ https://www.figma.com/community/file/946837271092540314/gov-uk-design-system シンプル、アクセシブル、スタイリッシュ、が実現されています。 スタイルとしては、ボタンの形状が角丸ではなく四角いのも特徴。 「Cookie banner」がコンポーネント化されているのもヨーロッパらしいです。 抽象面では、Principles(原則)も秀逸で、ポスターもあります。 https://www.gov.uk/guidance/government-design-principles https://github.com/alphagov/govdesign/blob/main/Poster_GovernmentDesignPrinciples.pdf アメリカ政府「U.S. Web Design System (USWDS)」 https://designsystem.digital.gov/ https://www.figma.com/@uswds 文字サイズ定義の最小がイギリス政府のものが16pxに対して、こちらは13pxです。 UI要素全般的に、イギリス政府に比べると小さい設計です。 これは、大きな国土、多くの人口、多様性、という背景から、訴訟社会、ローコンテクストな傾向にあるため、さまざまなシーンで説明的になる。つまり文章が長く、文字が多くなるのでしょう。 多くの情報が表現できることと、アクセシブルであることのバランスを定着させた事例と捉えています。 デジタル庁(日本) https://design.digital.go.jp/ https://www.figma.com/@digitalagencyjp イギリス政府のデザインシステムと同様に、シンプルで明快な印象のスタイルです。 UIコンポーネントの名称は「検索ボックス」「パンくずリスト」「日付ピッカー」のように、平易な表現となっています。 近い将来、各省庁をはじめ、多くの各行政機関のサイトが、このデザインシステムに沿って構築、運用されることを、期待しています。 日本の企業 SmartHR https://smarthr.design/ https://www.figma.com/community/file/978607227374353992 フルセットのデザインシステムです。 デザインシステムの構想、構築、運用を教えてくれる書籍「ちいさくはじめるデザインシステム」も出版されています。 https://bnn.co.jp/products/9784802512480 デザインシステムを学習、検討するなら必見です。 Ubie「Ubie Vitals」 https://vitals.ubie.life/ https://www.figma.com/design/ejIFAbw12HtoEZXcn01G5C/Ubie-UI https://www.figma.com/@ubie デザイン原則では「気軽」「かんたん」「誠実」「スッキリ」と謳われています。 その原則がドキュメントにも現れており、簡潔で把握しやすいです。 シンプルであるとともに、ライディングガイドライン、コンポーネント、GitHubでのコード公開など、ドキュメントの構成が行き届いています。 ライティングガイドラインには医療機関での問診の文例があり、アイコン集には形状の異なる複数の薬剤など「医療」という特定の分野に焦点あわせて設計された事例としても参考になります。 「Ubie Vitals」という名前は、医療用語の「バイタルサイン」に由来していると考えられ、デザインシステムの重要性と、医療分野へ注力していることが表されていると思います。 プラットフォーマー Google「Material Design」 https://m3.material.io/ https://www.figma.com/@materialdesign Android OS、Googleの各サービスが基本的にこれに則っており、一番利用されているUIかもしれません。 最も影響力のあるデザインシステムと言ってもよいでしょう。 Material DesignをReactで実装する際は、MUIが便利です。(MUIはMaterial Designのバージョン2を基にしています。) https://mui.com/ Apple「ヒューマンインターフェイスガイドライン(HIG)」 https://developer.apple.com/jp/design/human-interface-guidelines/ https://www.figma.com/@apple 「無料で公開されている資料」ではありますが、オープンソースではありません。 基本的には、iPhoneやMacなど、Apple製品向けアプリケーション開発を行う際に参照するドキュメントです。 「デザインシステム」という言葉が広く使われるようになったのは2010年代ですが、Appleは1980年代からHIGを定めています。 ユーザー体験を重視し、パソコンやスマートフォンを絶対的な価値に高めたメーカーが、どのような考え方でUI構築をしているのかを知ることができます。 スマートウォッチや、MR(複合現実)ヘッドセットのUIも含まれているのも特徴です。 IT分野、業務向け 各政府や、Google、Appleなどのデザインシステムが主に消費者向けなのに対し、IBM、GitHub、Atlassianの例は、複雑で大量の情報を扱うための効率性や機能性を追求した専門家向けです。 IBM「Carbon」 https://carbondesignsystem.com/ https://www.figma.com/@50ffba2e_c3b3_4 AI生成のコンテンツであることを示す「AI Label」コンポーネントも用意されています。 GitHub「Primer」 https://primer.style/ https://www.figma.com/community/file/854767373644076713 「Product UI」「Brand UI」に分けて設計されており、どちらも公開されています。 Atlassian https://atlassian.design/ https://www.figma.com/@atlassian 今回は、デザインシステムの基本的な捉え方から、公開されている優れた事例までを紹介しました。 まずは今回紹介したデザインシステムを実際に触ってみることから始めてみませんか?公開されたドキュメントを眺めるだけでも、UIデザインの新たな発見があるはずです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 良いプロダクトは「システム」でできている。デザインシステムとは何か? first appeared on SIOS Tech. Lab .
こんな方へ特におすすめ 勤怠管理システムへの申請、特に細かな作業時間の入力が面倒な方 タスクごとにどのくらいの時間がかかっているか、感覚でしか分からない方 簡単にPythonのアプリを開発したい方 概要 こんにちは。サイオステクノロジーのはらちゃんです!今回4本目のブログ執筆です。 今回は私が作成したストップウォッチアプリの紹介と、その開発過程、そして皆さんの勤怠管理や作業効率向上に役立つヒントをお伝えします。 なぜ自作ストップウォッチアプリが必要だったのか? 私の職場では、勤怠報告で作業の種類ごとに工数を確認する必要がありました。 「〇〇プロジェクトの設計」「△△タスクのコーディング」「定例会議」など、作業ごとに時間を測りたい──。 そんな想いから自分で作って自由にカスタムできるアプリを作ろうと考えました。 簡単!ストップウォッチの作り方 以下のような単純な機能をもつアプリを作っていこうと思います。 デスクトップに表示されます 機能としては上から ラベルに入力 タイマー表示 開始、停止ボタンのクリック タイマー個数の増減ボタンのクリック が行えます。 前提条件 VSCodeのインストール Pythonの開発環境 ステップ1:ホストOSの準備 まず、コンテナーのGUIをPC本体の画面に映し出すための「Xサーバー」というソフトをインストールします。これは初回のみ必要な作業です。 Xサーバーをインストールする。 Windowsの場合: VcXsrv をインストールして起動します。 Macの場合: XQuartz をインストールして起動します。 Display settings: 「 Multiple windows 」を選択して「次へ」。 Client startup: 「 Start no client 」を選択して「次へ」。 Extra settings: 「Disable access control」 に 必ずチェック を入れて「次へ」。 「完了」をクリックしてVcXsrvを起動します。 このような設定画面が起動します。 ステップ2:ストップウォッチアプリの実装 このPythonコードをコピーしてファイルに保存するだけですぐに動かすことができます。 stopwatch.py import tkinter as tk import time class StopwatchApp: def __init__(self, parent): # Frameを作成し、親ウィジェット(parent)に配置 self.frame = tk.Frame(parent) self.frame.pack(side=tk.LEFT, padx=15, pady=15) # --- ストップウォッチの状態を管理する変数 --- self.running = False self.start_time = 0.0 self.elapsed_time = 0.0 # --- ラベル編集部品 --- self.label_var = tk.StringVar() self.label_var.set("タイマー") self.label_entry = tk.Entry(self.frame, textvariable=self.label_var, font=("Arial", 10), justify="center", width=8) self.label_entry.pack(pady=(0,2)) # --- 画面の部品(ウィジェット)を作成 --- self.time_label = tk.Label(self.frame, text="00:00", font=("Arial", 40, "bold")) self.time_label.pack(pady=4) self.toggle_button = tk.Button(self.frame, text="Start", width=13, command=self.toggle) self.toggle_button.pack(pady=4) self.update() def toggle(self): """ボタンが押されたときの処理""" if self.running: # ストップ処理 self.running = False self.toggle_button.config(text="Start") else: # スタート処理 self.running = True self.toggle_button.config(text="Stop") self.start_time = time.time() - self.elapsed_time def update(self): """時間を計算して表示を更新する処理""" if self.running: self.elapsed_time = time.time() - self.start_time self._display_time() self.frame.after(10, self.update) def _display_time(self): """経過時間を見やすい形式に変換してラベルに表示(時間:分)""" hours = int(self.elapsed_time // 3600) minutes = int((self.elapsed_time % 3600) // 60) time_string = f"{hours:02}:{minutes:02}" self.time_label.config(text=time_string) # --- アプリケーションの実行 --- class StopwatchManager: def __init__(self, root): self.root = root self.stopwatches = [] self.frame = tk.Frame(root) self.frame.pack() # ボタン配置 btn_frame = tk.Frame(root) btn_frame.pack(pady=4) self.add_btn = tk.Button(btn_frame, text="○", font=("Arial", 12), width=4, command=self.add_stopwatch) self.add_btn.pack(side=tk.LEFT, padx=4) self.remove_btn = tk.Button(btn_frame, text="×", font=("Arial", 12), width=4, command=self.remove_stopwatch) self.remove_btn.pack(side=tk.LEFT, padx=4) # 初期2つ self.add_stopwatch() self.add_stopwatch() def add_stopwatch(self): sw = StopwatchApp(self.frame) self.stopwatches.append(sw) self.update_window_size() def remove_stopwatch(self): if self.stopwatches: sw = self.stopwatches.pop() sw.frame.destroy() self.update_window_size() def update_window_size(self): width = max(205 * len(self.stopwatches), 205) self.root.geometry(f"{width}x200") # --- アプリケーションの実行 --- if __name__ == "__main__": root = tk.Tk() root.title("StopWatch") root.resizable(False, False) root.attributes("-topmost", True) manager = StopwatchManager(root) # 初期ウィンドウサイズ root.geometry("410x200") root.mainloop() ステップ3:実行 ターミナルで以下のコマンドを入力するとアプリが起動します。 bash python3 stopwatch.py 実行できないときは… 解決策1:ライブラリのダウンロードする Pythonには「 Tkinter 」というGUI(画面付きアプリ)を作るためのライブラリが標準で付属しているため、追加のインストールなしですぐに開発を始められます。 しかし、Linuxで操作している場合は手動でのダウンロードが必要です。 bash sudo apt update sudo apt install python3 python3-tk 解決策2:ファイアウォールの設定を確認する VcXsrvを初めて起動したとき、Windows Defenderファイアウォールが警告画面を表示したはずです。 ここで「 アクセスを許可する 」を選択しないと、通信がブロックされてしまいます。 Windowsの検索バーで「 ファイアウォール 」と検索し、「 Windows Defender ファイアウォールによるアプリの許可 」を開きます。 「設定の変更」をクリックし、「別のアプリの許可」をクリックします。 「参照」からVcXsrvの実行ファイル(通常は C:\Program Files\VcXsrv\vcxsrv.exe )を選択して追加します。 一覧に追加された「vcxsrv」の「 プライベート 」と「 パブリック 」の両方のチェックボックスをオンにして「OK」をクリックします。 まとめ 今回は、ストップウォッチのアプリ開発を通して、PythonとTkinterを使えば、日常のちょっとした不便を解消するアプリを自作できる楽しさを学んでいきました。 Github でも、私の開発コードを公開しているので、自由にコードを書き替えて使ってみてくださいね。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 1人がこの投稿は役に立ったと言っています。 The post 勤怠管理の仕方|Tkinterで自作ストップウォッチ first appeared on SIOS Tech. Lab .
OSSよろずサポート担当の神﨑です。 今回は Dify についてソースコード、ドキュメント、検証を行った際の知見についてすでに公開されている弊社の記事と重ならない範囲で軽くまとめていきます。 Dify について Difyの概要や全体像については、 弊社エンジニアの解説記事 がありますので、ご参照ください。 Dify の呼称について 上記記事に掲載されていない一口メモとして Dify の読み方について説明します。 Dify のことを筆者は最近まで「ディファイ」と呼んでいましたが、正式な呼称は「ディフィ」となっております。 参考: https://xtech.nikkei.com/atcl/nxt/column/18/03236/061200004/ Dify + Amazon Bedrock について 弊社では AzureAI を利用した Dify の記事が数多く公開されていますが、今回は AWS の Amazon Bedrock という LLM で検証しました。 Dify で Amazon Bedrock を設定するやり方についても、 弊社エンジニアの解説記事 をご確認ください。 弊社で公開しているチャット bot やワークフロー、 RAG を作成してみましたが、問題なく動作しました。 アプリケーションを作成するうえでの注意点 Amazon Bedrock 上で有効化したモデル以外を選択した場合、LLM ノードにおいてエラーが出力されてしまうため有効化したモデルを正しく選択する必要があることにご注意ください。 Dify のエラー処理 Dify の各ノードで出力されるエラーについてまとめていきます。 参考: エラー処理 – エラータイプ概要 チャットフロー/ワークフロー システムエラー サービスが正しく起動していない、ネットワーク問題など 操作エラー ノードの設定や操作に失敗した際のエラー コードノード コードエラー(CodeNodeError) 開発者の設定したコード内にエラーがある場合に発生するエラー サンドボックスのネットワーク問題(System Error) ネットワークのトラフィックや 接続問題によって発生するエラー ネスト制限エラー(DepthLimitError) ノードのネスト構造が 5層以上の場合に発生するエラー 出力検証エラー(OutputValidatioのnError) 出力変数の型が一致しない場合に発生するエラー LLM ノード 変数が見つからない(VariableNotFoundError) 指定された変数が見つからない場合に発生するエラー コンテキスト構造の無効 (InvalidContextStructureError)   不正なデータ構造 (文字列以外) を受け取った場合に発生するエラー 無効な変数タイプ(InvalidVariableTypeError) システムプロンプトの形式が一般的なテキストや Jinja syntax でない場合に発生するエラー モデルが存在しない(ModelNotExistError) LLM ノードにモデルが設定されていない場合に発生するエラー  LLMの認証が必要(LLMModeRequiredError) 選択されたモデルに API キーが設定されていない場合に発生するエラー プロンプトが見つからない(NoPromptFoundError) LLM ノードのプロンプトが空の場合に発生するエラー HTTPノード 認証設定エラー(AuthorizationConfigError) 認証情報が設定されていない場合に発生するエラー ファイル取得エラー(FileFetchError) ファイル変数が取得できない場合に発生するエラー 不正なHTTPリクエストメソッド(InvalidHttpMethodError) リクエストメソッドが GET、HEAD、POST、PUT、PATCH、DELETE のいずれにも該当しない場合に発生するエラー レスポンスサイズ超過(ResponseSizeError) HTTPレスポンスコードエラー(HTTPResponseCodeError) レスポンスコードが 200系以外(例:400、404、500など)の場合に発生するエラー ※例外処理が有効であれば、これらのステータスコードによるエラーが報告される ツールノード ツール実行エラー(ToolNodeError) ツール自体の実行に問題があった場合に発生するエラー ツールパラメータエラー(ToolParameterError) ツールノードが要求するパラメータと異なる値が入力された場合に発生するエラー ツールファイル処理エラー(ToolFileError) ツールノードの処理に必要なファイルが見つからない場合に発生するエラー ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Dify のチュートリアルを終えての知見 (出力されたエラーなど) first appeared on SIOS Tech. Lab .
プリザンター® Pleasanter® は株式会社インプリムの登録商標です。 はじめに 今回は、9/19(金)に名古屋でオフライン開催された「 プリザンターハンズオンセミナー 」に参加してまいりましたので、そのレポートをさせていただきます。 本セミナーは、特にプリザンターを使ったことがない方や、使い始めたばかりの初心者の方向けの内容として構成されており、その基本操作を実際に手を動かしながら体験できる貴重な機会でした。 アイキャッチは当日いただいたアンブレラマーカー、クリアファイル、ステッカーです。 プリザンター® Pleasanter® は株式会社インプリムの登録商標です。 イベントの概要 本セミナーは名古屋にてオフライン形式で開催されました。 開催日時:2025年9月19日(金) 16:30〜18:00 会場:愛知県名古屋市中村区太閤1丁目20-13 秀幸ビル 6階 601号 (オフライン開催) 主催:株式会社インプリム 共催:プレシャスト株式会社 費用:無料 定員:15名(先着順) 60日間無料で全機能を試せるデモ環境 を使ってのハンズオンセミナーでした。 Pleasanter(プリザンター)とは Pleasanterはノーコードで業務アプリを作成できるプラットフォームです。Excelのような親しみやすい操作感で、プログラミングの知識がなくても簡単に業務アプリを作成することができます。顧客管理やプロジェクト管理、日報の管理などの散在しがちな情報を一元化して管理ができることが大きな特長です。 システム導入においても柔軟性が高く、クラウドでの利用はもちろん、インターネットに接続できないオンプレミス環境への導入にも対応しています。 Pleasanterの特徴的な機能 Pleasanterは、業務効率化と情報セキュリティを両立させる多様な機能を備えています。 進捗の可視化 標準機能としてガントチャートやカンバン機能なども搭載されており、業務の進捗状況の可視化、チーム内での情報共有を効率化することができます。 豊富なテンプレート 顧客情報、FAQ、資産管理など、幅広い業務に対応した業務アプリが多数用意されています。 通知・リマインド アプリケーション内の更新情報をメール通知したり、タスクの期日前にリマインド通知を送る設定も可能です。 アクセス制御 個人情報などの機密性の高い情報を、特定の担当者のみが閲覧・編集できるようにアクセス制御が可能です。 プリザンターでできること 成果物の紹介 今回のハンズオンでは案件管理で用いるアプリをプリザンターで作成しました。 ハンズオンでの成果物 今回主に作成したのは「フォルダ」と「テーブル」です。 「フォルダ」は皆さんが普段PCで使っているフォルダをイメージしていただけるとわかりやすいと思います。Pleasanterではテーブルや他のフォルダを格納しツリー構造でデータを管理します。 このフォルダの中にテーブルを作成することができます。テーブルは2種類あり、タスク管理などの期限の管理を行う「期限付きテーブル」と、資産管理などの情報の管理に使用する「記録テーブル」の二つがあります。テーブルの中には「レコード」を登録することができ、各タスクや記録の内容はこのレコードを登録することで管理されます。   今回のハンズオンでは「営業部」という名前のフォルダを作成し、その直下に「商談」という期限付きテーブルと「顧客マスタ」という記録テーブルを作成しました。作成した各テーブル内にレコードを作成し、商談情報や顧客情報を管理できるようにしました。 さらに、実践的な機能として、レコードへの画像の添付、テーブルに親子関係を持たせてのデータ連携、集計やフィルタの設定といった、実際の業務で役立つ操作も実施しました。 参加しての感想と所感 使用した感想としては、フォルダやテーブルの作成、テーブルの管理などの操作が直感的に分かりやすく、技術的な知識がない方でも操作しやすいと感じました。 個人的に便利だと感じたのは、テーブルの設計やレコードの内容を変更した際に更新を忘れるとダイアログが出るため、更新忘れがなく便利だと感じました。 セミナー全体を通して、進行のテンポが適正で、戸惑うことなく自分のペースで手を動かしやすかった点も、主催者様のご配慮を感じるポイントでした。 プリザンターのセミナーは、今回の名古屋開催のように各地で随時開催されております。ご興味をお持ちの方は、ぜひ参加されてみてはいかがでしょうか。 セミナー情報など 参考文献 Pleasanter Pleasanterの活用シーン Pleasanter導入事例 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【セミナーレポート】プリザンターハンズオンセミナー@名古屋に参加してきました! first appeared on SIOS Tech. Lab .
~史上最大級のnpm自己増殖型ワーム攻撃「Shai-Hulud」とその防御策~ 2025年9月15日、npmリポジトリに対する史上最大級のソフトウェアサプライチェーン攻撃「Shai-Hulud」が発見されました。この攻撃は、わずか1週間で20種類以上の悪意あるOSSパッケージを利用し、200万回以上ダウンロードされた大規模なものです。特にフィンテック企業(コイン取引所、銀行、証券など)が攻撃の対象とされることが多いとされています。 Shai-Huludは、従来の攻撃とは異なり、新しい自己増殖型マルウェア(ワーム)として自己拡散を続けます。攻撃は多段階で実行され、まずフィッシングによって開発者のGitHubやnpmトークンなどの認証情報を盗みます。開発者が感染パッケージをインストールし`postinstall`スクリプトが実行されると、悪意のあるコードが注入されます。 このコードは、環境内の機密データ(GitHubのPAT、SSHキー、AWS、GCP、Azureなどのクラウドプロバイダーのキー)を徹底的にスキャン(クレデンシャルハーベスティング)します。盗まれたデータは複数回エンコードされ、「Shai-Hulud」という名前のパブリックGitHubリポジトリなどに流出します。 最も危険な特徴は、ワームの拡散メカニズムです。有効なnpmトークンを発見すると、それを利用してメンテナが管理する他のパッケージの悪意あるバージョンを公開し、感染をエコシステム全体に広げる自己再生的なサイクルを生み出します。これは、npmエコシステムにおける最初の成功した自己増殖型ワームの一つであり、極めて深刻な脅威をもたらしています。 コミュニティベースのOSSは、その公開性や複雑な依存関係、セキュリティテストの不十分さ、コミュニティ内の信頼の悪用などから、サイバー攻撃の格好の標的となっています。 今回の事件では、多くのJFrogユーザー企業がこのリスクを防げたと報告されています。JFrog Platformは、ソフトウェアサプライチェーンのセキュリティガバナンスを全体的に守る統合プラットフォームであり、以下の主要な機能で防御策を提供します。 1. Curation機能: 悪意のあるパッケージがサプライチェーンに入る前にダウンロードを阻止する即時のガバナンスを提供します。 2. JFrog Xray: 現在の開発環境および本番環境のパッケージをリアルタイムスキャンし、「悪意度スコア」を付与して早期に脅威を発見・対策します。 3. Artifactoryのリモートリポジトリ機能: 外部パッケージリポジトリからのキャッシュを管理し、悪意あるアーティファクトの侵入を防ぎます。 もし影響を受けたパッケージをインストールしていた場合、GitHub、NPM、AWS、GCP、Azureなどで使用していたアクセストークンを直ちに回転させることが必須です。JFrogはこの脅威に対する研究を継続しています。 本記事の詳細は こちら からご確認ください ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 注意喚起:史上最大なNpmソフトウエアサプライチェーン攻撃:Shai-Hulud first appeared on SIOS Tech. Lab .
ここでは、連載形式で公開してきた「Git & GitLab入門」シリーズの記事へのリンクとともに、各回の概要を整理します。 Gitの基本とGitLab / GitHubについて バージョン管理の基盤となるGitの基本概念(リポジトリ、コミットなど)を解説し、そのツールであるGitと、プロジェクトをホストするGitLab/GitHubとの関係性を整理した入門連載の第1回です。 Git & GitLab 入門 (1) ~Git マスターへの道~「Git の基本と GitLab/GitHub」 Git操作入門 GitとVS Codeのインストールやユーザー設定といった環境構築から、ローカルリポジトリ上での変更・ステージング・コミットというバージョン管理の初歩的な操作手順を解説しています。 Git & GitLab 入門 (2) ~Git マスターへの道~「Git操作入門」 Git操作チーム利用コマンドや ロールバック チーム開発で必要となる履歴表示(git log)や差分確認(git diff)、タグ付け(git tag)、バージョン管理対象外の設定(.gitignore)といった操作と、状況に応じて使い分ける必要があるコミットを取り消すコマンド(git revert、git reset、git restore)について解説しています。 Git & GitLab 入門 (3) ~Git マスターへの道~「Git操作チーム利用コマンドや ロールバック」 リモートリポジトリとローカルリポジトリ リモートリポジトリの役割を解説し、SSHキーの登録、プロジェクトの作成、クローン、そしてローカルの変更をリモートへ反映させるadd/commit/pushといったリモートリポジトリとローカルリポジトリの連携操作を解説しています。 Git & GitLab 入門 (4) ~Git マスターへの道~「リモートリポジトリとローカルリポジトリ」 Git のブランチについて Gitのブランチの基本概念と、Git FlowやGitHub Flowなどの主要なブランチ戦略を解説し、チーム開発におけるマージリクエスト(プルリクエスト)の作成からコンフリクトの発生と手動による解消手順までを解説しています。 Git & GitLab 入門 (5) ~Git マスターへの道~「Git のブランチについて」 GitLabの画面説明とよく利用される機能説明 GitLabが提供する「プロジェクト」、CI/CD、セキュリティ機能、Issue管理やマージリクエストといったDevSecOpsライフサイクル全体をカバーする統合プラットフォームとしての主要な機能を、外部ツールとの連携を重視するGitHubとの違いを交えながら解説しています。 Git & GitLab 入門 (6) ~Git マスターへの道~「GitLabの画面説明とよく利用される機能説明」 GitLabのプロジェクトについて GitLabにおけるグループとプロジェクトの関係や、リポジトリとの違いを解説しています。また、マージリクエストやCI/CDを含むプロジェクトの統合的な機能を説明し、ユーザー招待や保護ブランチ、Wikiの設定といった開発を始めるための具体的な初期準備手順を解説しています。 Git & GitLab 入門 (7) ~Git マスターへの道~「GitLabのプロジェクトについて」 GitLabのCICD設定 継続的インテグレーション・継続的デリバリー(CI/CD)の概要を解説し、Kubernetes上にGitLab Runnerをセットアップして連携させた上で、.gitlab-ci.ymlを用いてコンテナイメージのビルド、プッシュ、デプロイメントまでを一貫して自動化するパイプラインの構築手順を解説しています。 Git & GitLab 入門 (8) ~Git マスターへの道~「GitLabのCICD設定」 コードレビューの進め方 GitLabのマージリクエスト(MR)をコードレビューの場として活用する方法を解説しており、レビュアーとレビューイ双方の視点から、レビューを円滑に進めるための具体的な手順(MR設定、コメント、承認、提案の適用)を解説しています。 Git & GitLab 入門 (9) ~Git マスターへの道~「コードレビューの進め方」 GitLabでDevSecOps 開発スピードと安全性を両立する「DevSecOps」の概念と、GitLabがCI/CDパイプラインへのセキュリティスキャン統合を通じてこれを実現し、Hilti社やCarfax社などの具体的な企業事例における開発効率化やセキュリティ向上といった導入成果を解説しています。 Git & GitLab 入門 (10) ~Git マスターへの道~「GitLabでDevSecOps」 この連載を通じて、Git/GitLabを利用した個人・チーム開発のプロセスを体系的に理解することができます。Gitの基本操作はもちろん、CI/CDやDevSecOps機能を組み込んだGitLabの基礎を学ぶことができます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Git & GitLab 入門 ~Git マスターへの道~「まとめ」 first appeared on SIOS Tech. Lab .
はじめに 昨今、生成AIが流行っているのは言うまでもありません。ChatGPTから始まり、そしてRAG(Retrieval Augmented Generation)と呼ばれる技術が注目され、さらにAIエージェントなんていうのも出てきています。そして、今、最も熱いのはMCP(Model Context Protocol)でしょう。 今回は、そんなMCPのテクノロジーとMoodle(オープンソースの学習管理システム)を組み合わせたMCPサーバーを作成しましたので、その紹介をしたいと思います。以下のGitリポジトリにてソースコードを公開しています。 https://github.com/ntakei-sti/moodle-mcp-server このMCPサーバーは、勉学に励む学生を優しく支えるAIツールです。 ざっくりいってしまうと、例えば下図のようにチャット形式のアプリにこのMCPサーバーを組み込むことで、学生がチャット形式で質問した内容に応じて、Moodleの情報を取得して、回答することができます。 例えば、このチャットみたいに、ちょっと弱気な発言をすると、過去の成績を鑑みて、オススメの教材を提案して励ましてくれたり、締切間近の宿題を忘れないように教えてくれたりします。 MCPサーバーとは? MCPとは、Model Context Protocolの略で、今流行りのAIエージェントに簡単に機能を追加するためのプロトコルです。 AIエージェントに関する詳しい説明は以下の記事を参考にしてください。 https://tech-lab.sios.jp/archives/42867 そして、このMCPというプロコトルに準拠して作成されたサーバーがMCPサーバーです。 では、このMCPサーバーの機能を理解するために、「MCPがない世界」と「MCPがある世界」を比較してみましょう。 MCPがない世界 MCPがない世界では、他のAIエージェントAでとても役立つ機能を使っていたとして、それをいざAIエージェントBで使おうとした場合、AIエージェントB向けにその機能を実装し直す必要があります。 というのは、今まではLLMアプリ(DifyやClaudeなど)はそれぞれ独自の実装方式を持っており、またAIエージェントが使うツールもそれぞれ独自の実装方式をもっており、それぞれの実装方式に合わせて、ツールの方を改修する必要がありました。 例えばAIエージェントAではクラウドストレージにアクセスして、ファイルの一覧や中身を取得する機能があったとしても、AIエージェントBではそのクラウドストレージにアクセスする方法が異なっている場合、AIエージェントB向けにクラウドストレージにアクセスする機能を実装し直す必要があります。 MCPがある世界 MCPがある世界では、AIエージェントAで実装した機能をそのままAIエージェントBでも利用することができます。なぜなら、MCPに準拠したインターフェースを通じて、異なるAIエージェント間で機能を共有できるからです。 ここでは、「MCPサーバーがない世界」で「ツール」と言われていたものは「MCPサーバー」と呼ばれるようになりました。当然「サーバー」と呼ばれるくらいなので、それにラクセスするクライアントである「MCPクライアント」も必要になります。 MCPクライントとMCPサーバーを用意し、その間の通信をMCPに準拠したものにして、MCPサーバー側ではインターネットやクラウドストレージなど各種リソースにアクセスして、MCPクライアントに結果を返すようにします。 このようにして、MCPサーバーを用意することで、異なるAIエージェント間で機能を共有できるようになります。 今回の記事では、MCPの話が本筋ではないので、MCPに関する詳しい説明は割愛します。MCPに関する詳しい説明は以下のYouTubeを参考にしてください。 https://www.youtube.com/live/f7x6flxAfak?si=XDNt7xYWWpaZVHkP Moodleとは? Moodle(ムードル)は、学校や企業の学習をオンラインで運営するための「学習管理システム(LMS)」です。オープンソースで無償利用でき、ブラウザさえあれば受講から課題提出、採点、成績管理まで一通り行えます。 主な登場人物は管理者・教師・学習者の3つになります。 管理者はサイトやユーザーを統括したり、Moodleの基本的な設定(権限管理やメールサーバーなどの設定)を行います。 教師はコース(科目)を作って教材やテストを配置し、学生への各種伝達、課題の提出管理や採点を行います。 学習者は学生のことで、教師からの指示に基づいて、課題などの受講・提出・確認を行います。 ざっくりこんな流れ このMCPサーバーの処理の流れをざっくり説明します。 ① 認証 ユーザーがIdPで認証します。このIdPはKeyCloakやOktaなどのOpenID Connectに対応したものの利用を想定しています。 ② 質問 LLMアプリ(DifyやClaudeなど)で質問します。このとき①で取得したIDトークンをHTTPヘッダー Authorization にセットして、LLMアプリに渡します。 ③ ツール取得 MCPのプロトコルに則り、MCPクライアントからMCPサーバーに対して、利用可能なツールの一覧を取得します。 ④ ツール選定 ③で取得したツール一覧をAzure OpenAI ServiceなどのLLMに渡し、質問に対して適切なツールを選定します。 ⑤ ツール返却 LLMから返却されたツールをLLMアプリが受け取ります。 ⑥ ツール呼び出し LLMアプリがMCPクライアントを通じて、MCPサーバーに対してツールを呼び出します。このとき、②で取得したIDトークンをもとに、MCPサーバーに対して、ユーザー情報を渡します。 ⑦ API実行 MCPサーバーはユーザー情報やコース情報などをもとに、MoodleのREST APIを呼び出して、必要な情報を取得します。 MCPサーバーの基本機能 今回作成したMCPサーバーは、MoodleのREST APIを利用して、Moodleの情報を取得する機能を持っております。具体的には以下の機能を提供しています。 ■  成績が低い課題のコースに関するファイル一覧を取得 ユーザーの履修コースのうち、成績の回答率が 一定値を下回るコースに添付されたファイルを列挙します。 ■ 未提出の課題の取得 ユーザーの未提出と判定される課題を検索して返します。 ■ ユーザーが履修しているコース一覧の取得 ユーザーが履修しているコースの一覧を取得します。 ■ コース検索 全コースからキーワード検索を行います。表示名(displayname)や概要(summary)も出力に含めます。 ■ 締め切り間近の課題取得 ユーザーの未提出と判定される課題のうち、締め切りが近いものを検索して返します。 MCPサーバーの詳細機能 MCPサーバーのより詳細な機能について説明します。 get_resources_under_specific_grade ユーザーの履修コースのうち、成績の回答率が環境変数 COMPLETION_THRESHOLD を下回るコースに添付されたファイルを列挙します。 ユーザー名は REMOTE_USER 環境変数、または X-Remote-User ヘッダー、あるいは ID トークンで指定します。 get_my_unsubmitted_assignments ユーザーの未提出と判定される課題を検索して返します。課題の提出判定には 環境変数 mod_assign_get_submission_status を優先利用し、 ユーザー名は REMOTE_USER 環境変数、または X-Remote-User ヘッダー、あるいは ID トークンで指定します。 get_my_enrolled_courses ユーザーが履修しているコース一覧を返します。 ユーザー名は REMOTE_USER 環境変数、または X-Remote-User ヘッダー、あるいは ID トークンで指定します。 find_my_courses_by_keyword(keyword) core_course_search_courses を利用して全コースからキーワード検索を行います。表示名(displayname)や概要(summary)も出力に含めます。 get_upcoming_deadlines 環境変数 UPCOMING_DEADLINES_DAYS 日以内に締切が来る課題を集約して返します。 mod_assign_get_assignments を優先して使い、 フォールバックで gradereport から締切を探します。 ユーザー名は REMOTE_USER 環境変数、または X-Remote-User ヘッダー、あるいは ID トークンで指定します。 システム構成 このMCPサーバーで構成することの出来るシステム構成の例をいくつか紹介します。 信頼できるネットワーク内にMCPクライントとMCPサーバーがある場合 この場合、MCPクライアントとMCPサーバーは同じ信頼できるネットワーク内にあるため、つまり、このMCPサーバーにアクセスできるのは、LLMアプリのみのため、HTTPヘッダー X-Remote-User を使ってユーザー名を渡すことができます。 後述するIDトークンを使う場合と比べて、LLMアプリの実装が簡単になります。 信頼できるネットワーク外にMCPクライントとMCPサーバーがある場合 この場合、MCPクライアントとMCPサーバーは同じ信頼できるネットワーク内にはないため、つまり、このMCPサーバーにアクセスできるのは、不特定多数のユーザーが利用する可能性があるため、HTTPヘッダー X-Remote-User を使ってユーザー名を渡すことはできません。 この場合、IDトークンを使ってユーザー名を渡す必要があります。MCPサーバーはIDトークンを検証し、ユーザー名を取得します。 MCPクライアントとMCPサーバーが同じアプリケーションサーバー上にある場合 この場合、MCPクライアントとMCPサーバーは同じアプリケーションサーバー上にあるため、通信方式としてSTDIOを用います。環境変数 REMOTE_USER を使ってユーザー名を渡すことができます。 起動方法 このMCPサーバーはPythonで作成されており、 pip コマンドでインストールして利用します。 事前準備 以下のコマンドを実行して、必要なライブラリをインストールしてください。 $ git clone https://hogehoge.git $ cd moodle-mcp-server $ ppip install -r requirements.txt 環境変数の設定 このプロジェクトは環境変数で各種挙動を制御します。 .env  ファイルを作成するか、シェルの環境変数として設定してください。通信方式(MCP_TRANSPORT)により必要な環境変数が異なります。 共通 MOODLE_API_URL (必須): Moodle サイトのベース URL(例: < https://moodle.example.com >) MOODLE_WSTOKEN (必須): Moodle の Webservice トークン COMPLETION_THRESHOLD (任意): 成績の「回答率」閾値(デフォルト 80) UPCOMING_DEADLINES_DAYS (任意): get_upcoming_deadlines が参照する日数ウィンドウ(デフォルト 7) MCP_TRANSPORT (任意): 通信方式。 sse (既定)または stdio SSE モード(MCP_TRANSPORT=sse)もしくはStreamable HTTPモード(MCP_TRANSPORT=streamable-http)で主に使用する変数 MCP_SERVER_HOST (任意): サーバのバインドアドレス(デフォルト 0.0.0.0 ) MCP_SERVER_PORT (任意): サーバのポート(デフォルト 8000 ) ACCEPT_REMOTE_USER_HEADERS (任意): true で X-Remote-User ヘッダを優先(デフォルト true ) Bearer トークン検証を使う場合に必要: OIDC_METADATA_URL : OpenID Provider のメタデータ URL(必須) OIDC_AUDIENCE (任意): 期待する audience OIDC_USERNAME_CLAIM (任意): ユーザー識別子に使うクレーム名(デフォルト sub ) STDIO モード(MCP_TRANSPORT=stdio)で使用する変数 REMOTE_USER (必須): 実行中プロセスで扱う Moodle の username 注意: ACCEPT_REMOTE_USER_HEADERS を有効にする場合、 リモートヘッダは信頼できるプロキシからのみ渡す  ようにしてください。 例: `.env` ファイルテンプレート(SSEもしくはStreamable HTTP) MOODLE_API_URL=https://moodle.example.com MOODLE_WSTOKEN=your_moodle_ws_token COMPLETION_THRESHOLD=80 OIDC_METADATA_URL=https://idp.example.com/.well-known/openid-configuration OIDC_AUDIENCE=your-client-id OIDC_USERNAME_CLAIM=preferred_username ACCEPT_REMOTE_USER_HEADERS=true UPCOMING_DEADLINES_DAYS=7 MCP_TRANSPORT=sse MCP_SERVER_HOST=0.0.0.0 MCP_SERVER_PORT=8000 例: `.env` ファイルテンプレート(STDIO) MOODLE_API_URL=https://moodle.example.com MOODLE_WSTOKEN=your_moodle_ws_token REMOTE_USER=your-username MCP_TRANSPORT=stdio 起動 以下のコマンドを実行して、MCPサーバーを起動します。 $ python moodle_mcpserver.py 動作確認 MCP Inspectorというツールを使うと簡単に動作確認ができます。MCP InspectorはMCPサーバーに対して、MCPのプロトコルに則った通信を行うことができるツールです。動作するためにはNode.jsの環境が必要です。 以下のコマンドでMCP Inspectorを起動します。 $ npx @modelcontextprotocol/inspector STDIOで動作確認する場合 まず基本的な設定を行います。 ① Transportで `stdio` を選択します。 ② Commandに `python ` を選択します。 ③ Commandにmoodle_mcp_server.pyのパスを入力します。 ④ `MOODLE_API_URL` 、 `MOODLE_WSTOKEN` 、 `REMOTE_USER` の環境変数を設定します。 MCPサーバーに接続します。 `Connect` ボタンを押します。   ツールの一覧を取得して実行します。 `Tools` タブを選択し(①)、 `List Tools` ボタンを押します(②)。ツールの一覧が取得されます(③)。ツールを選んで、 `Run Tool` ボタンを押すと、ツールが実行されます(④)。   ツールの実行に成功すると、以下のように結果が表示されます。 Stremable HTTPもしくはSSEで動作確認する場合 まず基本的な設定を行います。 ① Transport Typeは、 `Streamable HTTP` もしくは `sse` を選択します。 ② Transport Typeが `Streamable HTTP` の場合、 `http://[MCPサーバーのホスト名]/mcp` を入力します。Transport Typeが `sse` の場合、 `http://[MCPサーバーのホスト名]/sse` を入力します。 ③ HTTPヘッダを追加します。 `ACCEPT_REMOTE_USER_HEADERS` を `true` に設定している場合、 `X-Remote-User` ヘッダーを追加します。IDトークンを使う場合、 `Authorization` ヘッダーを追加します。両方とも値はMoodleのユーザー名です。 ⑤ `Connect` ボタンを押します。 後の手順は、STDIOで動作確認する場合と同様です。 より実践的なシステムを構築 簡単な動作確認が出来たところで、このMCPサーバーを動かすための、より実践的なシステムを構築してみましょう。以下の図がそのシステム構成です。 LLM アプリとして Dify を利用します。Dify は MCP に対応しているため、MCP クライアントとして動作します。 Dify 自体には認証機能がないため、別途チャット UI を提供するアプリケーションサーバーを用意します。ここでは Streamlit を利用します。Streamlit は OpenID Connect に対応しているため、KeyCloak でユーザーを認証した後に ID トークンを取得できます。 ユーザーが認証を終えると、取得した ID トークンが Streamlit に渡され、Streamlit 側でトークンの検証を行い、Moodle のユーザー名を取得します。そのうえで Streamlit から Dify に対して API を呼び出します。Dify は公開 API を提供しており、そこに質問を送ることで回答を得ることができます。この際、ID トークンから取得したユーザー名を API のパラメーターとして渡すことで、Dify がユーザー名を認識できるようにします。 Dify は MCP クライアントとして、MCP サーバーに対して Moodle の情報を取得するためのツール一覧の取得やツール実行を行います。ここから先は MCP のプロトコルに従って通信が進みます。 では構築手順を説明していきます。 KeyCloakの設定 クライアントを作成するために、KeyCloakの管理コンソールにログインし、 `Clients` メニューから、 `Create client` ボタンを押します。   `Client ID` に任意の名称を入力し、 `Next` ボタンを押します。   `Client authentication` を `ON` (①)、 `Authorization` を `OFF` (②)にしてクライアントシークレットによる認証を有効にします。認可コードフローに対応するために、 `Standrd flow` にチェックを入れます(③)。最後に `Next` ボタンを押します(④)。   Valid redirect URIsに `http[s]://[Streamlitのホスト名]/oauth2callback` を入力し(①)、 `Save` ボタンを押します(②)。   クライアントシークレットを確認するために、 `Credentials` タブを選択します(①)。 `Secret` の値を控えておきます(②)。後でStreamlitの設定で利用します。 Streamlitの設定 Streamlitでは、KeyCloakなどのOpenID Connectに対応したIdPを利用して、ユーザー認証を行い、DifyのAPIを呼び出す必要があります。このアプリケーションは、以下のGitHubリポジトリで公開していますので、Cloneして利用してください。 https://github.com/ntakei-sti/streamlit4dify Cloneしたら、まず、 `.env` を以下のように設定します。 `DIFY_API_URL` はDifyのAPIエンドポイントを指定します。 `DIFY_API_KEY` はDifyのAPIキーを指定します。 `OIDC_USERNAME_CLAIM` はKeyCloakのユーザー名に対応するクレーム名を指定します。KeyCloakのデフォルトでは `preferred_username` ですが、環境によって異なる場合がありますので、適宜変更してください。 DIFY_API_URL=http[s]://<Difyのホスト名>/v1/chat-messages DIFY_API_KEY=<DifyのAPIキー> OIDC_USERNAME_CLAIM=<KeyCloakのユーザー名に対応するクレーム名>   次に、 `secrets.toml` を以下のように設定します。 `redirect_uri` はKeyCloakのクライアント設定で指定した `Valid redirect URIs` を指定します。 `cookie_secret` は任意の文字列を指定します。 `client_id` はKeyCloakのクライアントIDを指定します。 `client_secret` はKeyCloakのクライアントシークレットを指定します。 `server_metadata_url` はKeyCloakのメタデータURLを指定します。 [auth] redirect_uri = "http[s]://<Streamlitのホスト名>/oauth2callback" cookie_secret = "<任意の文字列>" client_id = "<KeyCloakのクライアントID>" client_secret = "<KeyCloakのクライアントシークレット>" server_metadata_url = "http[s]://<KeyCloakのホスト名>/realms/<レルム名>/.well-known/openid-configuration"   Streamlitアプリケーションを起動します。 $ streamlit run app.py Dify設定 まず、DifyのマーケットプレイスからMCPプラグインをインストールします。Difyの管理コンソールにログインし、 `Plugins` メニューから、 `Agent Strategies` のプラグインをインストールします。   そして、ワークフロー内でMCPプラグインを利用するように設定します。 `Agent` というブロックが追加出来るようになっているので、これをワークフローに追加します。   `Agentic Strategy` は `Function Calling (Support MCP Tools)` を選択します(①)。 `MCP SERVERS CONFIG` は、以下のように設定します(②)。 {   "server_name1": {   "transport": "sse", "headers": { "X-Remote-User": 🏡Start/{x}sys.user_id }, "url": "http[s]://<MCPサーバーのホスト名>/sse" } }   `INSTRUCTIONS` は以下のように設定します(③)。このシステムメッセージを定義することにより、ユーザーの弱気な発言を拾って、Moodleの情報を取得して、優しく励ますことができます。 あなたはmoodleからいろんな情報を取得する賢いエージェントです。 ユーザーが、「成績が出なくて困った」などの類の弱気な趣旨の質問をした場合には、ツールget_resources_under_specific_gradeを呼んでください。その回答は、成績が思わしく無いコースの資料ですので、それらの資料を優しく提案してあげてください。 MCPサーバーの設定 MCPサーバーを起動します。起動するための環境変数の説明は説明済みですので割愛します。今回の構成では、通信方式をSSE、MCPサーバーはDifyからのみアクセスされることを前提として、 `ACCEPT_REMOTE_USER_HEADERS` を `true` に設定します。以下は `.env` ファイルの例です。 MOODLE_API_URL=<MoodleのURL> MOODLE_WSTOKEN=<MoodleのWebサービスのトークン> COMPLETION_THRESHOLD=80 MCP_TRANSPORT=sse ACCEPT_REMOTE_USER_HEADERS=true MCPサーバーを起動します。 $ python moodle_mcp_server.py 動作確認 Streamlitのアプリケーションにアクセスします。KeyCloakのログイン画面が表示されるので、ユーザー名とパスワードを入力してログインします。   KeyCloakのログイン画面が表示されるので、ユーザー名とパスワードを入力してログインします。   ログインに成功すると、チャット画面が表示されます。チャット画面で質問を入力して、 `Send` ボタンを押します。 まとめ いかがでしたでしょうか?勉学に励む学生を優しく包むAIって素敵ですね。ときに厳しく、そして特に優しく、学生を支えるMoodle対応のMCPサーバーをぜひご活用ください。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 生成AIの学術利用を加速する!!勉学に励む学生を優しくサポートするMoodle対応のMCPサーバーを作りました!! first appeared on SIOS Tech. Lab .
はじめに 前回の記事では、GitLabとOpenShift、Gatekeeperを組み合わせたDevSecOpsモデルケース環境の構築方法を紹介しました。   本記事では、それらを組み合わせて閉域環境におけるDevSecOpsモデルケースを構築し、デモアプリを使ってCI/CDの流れにセキュリティがどのように組み込まれるのかを確認します。   金融や公共分野など高いセキュリティ要件が求められるシステムでは、インターネット非接続の環境であっても、開発のスピードと安全性を両立することが求められます。 GitLabとGatekeeperを活用することで、この課題をどのように解決できるのかを具体的に示すのが今回の目的です。 DevSecOpsとは、DevOpsの迅速な開発・運用プロセスに「セキュリティ」を組み込み、スピードと安全性を両立させる手法です。従来は「開発が完了した後にセキュリティチェックを行う」ことが一般的でした。しかしこの方法では、最終段階で脆弱性が見つかった際に大きな修正が必要となり、時間やコストの増大、リリースの遅延を招いてしまいます。 DevSecOpsでは、開発ライフサイクルの各段階にセキュリティを統合することで、早い段階からリスクを検知し、小規模な修正で対処できます。その結果、開発のスピードを維持しながら、コスト削減と安全性の向上を同時に実現できます。 DevSecOpsは、下図のように開発(Dev)と運用(Ops)のライフサイクルにセキュリティ(Sec)を組み込む考え方です。 DevSecOpsの詳細については以下の記事で解説していますので、ご参照ください。 DevSecOpsとは?安全性とスピードを両立する開発手法 | SIOS Tech. Lab 本記事のデモは、以下の流れで進めます。 ゴール 本記事のゴールは次のとおりです。 DevSecOpsのライフサイクルを実際のCI/CDパイプラインを通じて理解する GitLabとGatekeeperを組み合わせたセキュリティ統制の仕組みを把握する 前提条件 本記事のデモンストレーションは、以下の環境を前提としています。 GitLab サーバー(ソースコード管理・CI/CD実行) OpenShift クラスター(閉域環境にて構築済み、アプリケーション実行環境) GitLab Runner(OpenShift 内にデプロイ済み) Gatekeeper(OpenShift 内にデプロイ済み、リソース作成許可ポリシーを定義済み) 踏み台サーバー(クラスターへのアクセス用) これらは前回の記事「 構築編 」で構築したモデルケース環境に含まれています。 構築手順の詳細は「構築編」を参照してください。 デモアプリの仕様 ベースイメージ:nginx サービス提供ポート:8080 到達性:内部ネットワークのみアクセス可能(外部公開なし) デプロイ方式:Helm(Chart・valuesでイメージタグを切り替え) デモで使用するタグ:v1.0(初回デプロイ)、v1.1(修正デプロイ) パイプラインの実行フロー 今回利用するCI/CDパイプラインの実行フローは以下の通りです。 ビルド用パイプライン実行フロー 開発者がGitLabのビルド用プロジェクトにブランチをマージ マージをトリガーとして、GitLab CI/CDパイプラインが起動 GitLab CI/CDからOpenShiftクラスター内のGitLab Runnerへビルドジョブ実行リクエストを送信 RunnerがジョブPodを起動 ジョブPodがビルド用プロジェクトからアプリのソースコードをClone ジョブPodがdocker CLIなどを利用してコンテナイメージをビルド ジョブPodがビルドしたイメージをGitLabのビルド用プロジェクト内のレジストリにpush デプロイ用パイプライン実行フロー 開発者がGitLabのデプロイ用プロジェクトにブランチをマージ マージをトリガーとして、GitLab CI/CDパイプラインが起動 GitLab CI/CDからOpenShiftクラスター内のGitLab Runnerへデプロイジョブ実行リクエストを送信 RunnerがジョブPodを起動 ジョブPodがOpenShiftのAPIサーバーに対し、リソースのデプロイリクエストを送信 APIサーバーがGitLabのレジストリからアプリのイメージをpull APIサーバーがOpenShiftクラスター内にアプリをデプロイ DevSecOpsのデモンストレーション ここからは、構築済みのモデルケース環境を使って、実際にDevSecOpsの流れを確認します。 以下のように、アプリのデプロイを2回繰り返し、最後にGatekeeperによる制御を体験します。 アプリの初回アップロード(v1.0 デプロイ) アプリを修正して再度デプロイ(v1.1 デプロイ) Gatekeeperによる不正リソース作成の拒否 アプリケーションの初回デプロイ ここからは、DevSecOpsライフサイクルのCode → Operate(1週目)に対応します。 まず、アプリの初回デプロイを行います。 コードを ビルド用プロジェクト のfeatureブランチにpushし、developブランチへマージします。 developブランチにマージすると、コンテナイメージをビルドするパイプラインが起動します。 この操作によって、開発用のイメージ(dev-v1.0)がビルドされます。  続いて、 デプロイ用プロジェクト のfeatureブランチをdevelop ブランチへマージします。 これにより、先ほどビルドされたv1.0イメージを利用して、開発用Namespaceにアプリがデプロイされます。 $ oc get pod -n devsecops-develop -l app="nginx" NAME                                READY   STATUS    RESTARTS   AGE nginx-deployment-5d75b659c5-cqbqp   1/1     Running   0          118s 動作確認が完了したら、ビルド用プロジェクトのdevelopブランチからmainブランチへのマージリクエストを作成し、承認後にマージします。 mainブランチにマージすると、パイプラインが起動し、prod-v1.0イメージがレジストリに格納されます。 次にデプロイ用プロジェクトでdevelopブランチをmainブランチにマージすると、パイプラインが起動し、本番環境用のネームスペースにアプリをデプロイします。 その結果、本番環境にアプリがデプロイされ、表示内容を確認できれば、 Code → Operate の1週目(v1.0)が完了 です。 $ oc get pod -n devsecops-production -l app="nginx" NAME                                READY   STATUS    RESTARTS   AGE nginx-deployment-6c49676b47-m96pf   1/1     Running   0          29s nginx-deployment-6c49676b47-pzv96   1/1     Running   0          29s アプリケーションを修正して再度デプロイ ここからは、DevSecOpsライフサイクルのCode → Operate(2週目)に対応します。 アプリを修正します。ここではindex.htmlの内容を更新し、あわせて.gitlab-ci.ymlで定義しているコンテナイメージのタグをv1.1に変更します。 次に、 ビルド用プロジェクト のfeatureブランチにpushし、developブランチへマージします。 この操作によって、新しい開発用イメージ(v1.1)がビルドされます。 続いて、 デプロイ用プロジェクト のfeatureブランチでConfig/develop-values.yamlと Config/product-values.yamlのtagを修正し、反映します。その後、同様にdevelopブランチ へマージして変更を適用します。 これにより、先ほどビルドされたv1.1イメージを利用して、開発用Namespaceにアプリがデプロイされます。 $ oc describe pod -n devsecops-develop nginx-deployment-54d94596b6-8j8w6 | grep "Image:"     Image:          registry.gitlab.local.example.com/devsecops-user/devsecops-build-project/nginx:dev-v1.1 動作確認が完了したら、developブランチからmainブランチへのマージリクエストを作成し、承認後にマージします。 その結果、本番環境に修正版アプリがデプロイされ、表示内容が更新されていることを確認できます。 $ oc describe pod -n devsecops-production nginx-deployment-59ddc6dbb6-lhd6b | grep "Image:"     Image:          registry.gitlab.local.example.com/devsecops-user/devsecops-build-project/nginx:prod-v1.1 この時点で、 Code → Operate の2週目(v1.1)が完了 です。 Gatekeeperによる不正リソースの検知・拒否 ここからは、DevSecOpsライフサイクルのSecに対応します。 最後に、あえて不正な設定を持つリソースをNamespaceにデプロイしてみます。 Gatekeeperのポリシー設定で、 envラベルの値がデプロイ先のnamespace名と一致していないとPodの作成を許可しない 制約 を設定しています。 以下のように、 デプロイ用プロジェクト でdeploymentのlabelsでenvラベルを不正な値に書き換える修正を行い、developブランチにマージします。 このときGatekeeperのポリシーが働き、不正なリソースの作成は拒否されます。 実際のログやイベントを確認すると、Constraint によって違反が検出され、Podのデプロイが失敗していることが分かります。   一番下のReplicaSetはDesired 1に対して、Currentが0であり、Podがデプロイされていないことがわかります。 $ oc get replicasets.apps -n devsecops-develop  NAME                          DESIRED   CURRENT   READY   AGE nginx-deployment-54d94596b6   1         1         1       20m nginx-deployment-5d75b659c5   0         0         0       14h nginx-deployment-6bfd599796   1         0         0       3m48s PodがデプロイされていないReplicaSetのイベントを確認すると、Gatekeeperの 制約テンプレート で設定したエラーメッセージが表示されていることがわかります。 $ oc describe replicasets.apps -n devsecops-develop nginx-deployment-6bfd599796 Events:   Type     Reason        Age                 From                   Message   ----     ------        ----                ----                   -------   Warning  FailedCreate  4m13s               replicaset-controller  Error creating: admission webhook "validation.gatekeeper.sh" denied the request: [require-env-label-match-namespace] Pod 'nginx-deployment-6bfd599796-z7hgf' の 'env' ラベルの値は、Namespace名 'devsecops-develop' と一致する必要があります。現在の値は 'dummy-env' です。 このように、 開発者が意識しなくてもポリシー違反が自動的にブロックされる ことで、セキュリティを犠牲にせずに CI/CD のスピードを維持できることを体験できます。 まとめ 本記事では、GitLab、OpenShift、Gatekeeperを組み合わせて閉域環境にDevSecOpsモデルケースを構築し、デモアプリを用いて以下の流れを確認しました。 GitLab CI/CDによるアプリケーションデプロイの自動化   コード変更からの継続的デリバリー   Gatekeeperポリシーによるセキュリティ担保   このデモを通じて、次のポイントを押さえることができました。 DevOpsだけでは不十分 開発サイクルが迅速化しても、不正なリソースや設定が混入すれば安全性は損なわれる。 ポリシー制御の仕組みが重要 Gatekeeperを用いることで、開発の初期段階から不正なリソースを自動的に排除できる。 GitLabとOpenShiftの統合は実用的 インターネット非接続の閉域環境でも再現可能であり、金融・公共分野を含む実案件にも応用できる。 さらに実環境での利用を考えるなら、コンテナイメージのセキュリティスキャンや、より複雑なポリシー制御を組み合わせることで、より強固なDevSecOpsを実現できます。   まずは小規模なモデルケースから試し、徐々に自社の環境や要件に合わせて拡張していくことをおすすめします。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post DevSecOps実践ガイド:セキュアなCI/CD運用の実践編 first appeared on SIOS Tech. Lab .
はじめに 前回までに、GitLabとOpenShift、Gatekeeperを閉域環境で構築する手順を紹介しました。 本記事では、その環境を基盤としてGitLabのプロジェクト作成や設定を追加し、CI/CDパイプラインとポリシー検証を組み合わせたDevSecOpsの実践例に向けた環境構築を行います。 特に、金融や公共分野のように高いセキュリティ要件が求められるシステムでは、インターネット非接続環境での開発・運用が前提となるケースが多くあります。本記事で取り上げる構成は、そうした制約下でも有効な実践例となります。 なお、本記事では構築の全手順を網羅するのではなく、モデルケースの全体像と主要な構成要素を中心に解説します。詳細な設定値やコードについては、 こちらのリポジトリ をご参照ください。 ゴール GitLabにビルド用・デプロイ用プロジェクトを作成する OpenShiftのNamespaceや権限を設定する Gatekeeperのポリシーを適用し、CI/CDパイプライン実行時にポリシー違反を検知できるようにする 次回のデモ実演に向けた基盤を完成させる DevSecOpsとは? DevSecOpsとは、DevOpsの迅速な開発・運用プロセスにセキュリティを統合することで、スピードと安全性を両立する手法です。 従来の「開発の後にセキュリティチェックを行う」アプローチではなく、開発ライフサイクルの各段階にセキュリティを組み込む点が特徴です。 詳細については以下の記事で解説していますので、ご参照ください。 DevSecOpsとは?安全性とスピードを両立する開発手法 | SIOS Tech. Lab 前提条件 以下の記事の手順に従って、環境構築が完了していること GitLabとコンテナプラットフォームの連携 | SIOS Tech. Lab OPA/Gatekeeperで始める安心OpenShift運用:構築編 デモアプリの仕様 ベースイメージ:nginx サービス提供ポート:8080 到達性:内部ネットワークのみアクセス可能(外部公開なし) デプロイ方式:Helm(Chart・valuesでイメージタグを切り替え) サンプル構成の全体像 プロジェクトの分割方針 devsecops-build-project(ビルド用) ソースコードとDockerfileを管理し、イメージをビルドしてGitLab Container Registryにpushします。 devsecops-deploy-project(デプロイ用) Helmチャートと環境別のvaluesファイルを管理し、Registryのイメージを参照してOpenShiftにデプロイします。 このように ビルドとデプロイを分けることで、開発コードの管理とデプロイ設定の管理を明確に切り分けられるようにしています。 リポジトリ構成(概要) ビルド用リポジトリ Containerfileとsrc/ : Nginxベースのアプリ .gitlab-ci.yml : イメージビルド&レジストリへpush デプロイ用リポジトリ devsecops-nginx-chart/ : Helmチャート develop-values.yamlとproduct-values.yaml : 環境別設定 .gitlab-ci.yml : Helmを使ったOpenShiftへのアプリのデプロイ ※詳細なディレクトリとファイル内容は こちらのリポジトリ をご覧ください。 ブランチ戦略 feature/* : 開発作業用ブランチ develop : 開発環境に対応 main : 本番環境に対応 feature → develop → main の流れでレビューを経たマージを行い、保護ブランチ設定によりdevelopやmainブランチへの直接pushは禁止しています。 パイプラインの流れ ビルドパイプライン(build-project) ソースコード変更を検知 Runnerがイメージをビルドし、レジストリにpush デプロイパイプライン(deploy-project) Helm設定変更を検知 Runnerがレジストリのイメージをpullし、OpenShiftにデプロイ Gatekeeperがポリシーを検証し、違反があればリソース作成を拒否 構築手順(概要) 手順の流れ 今回のサンプルケースでは以下の構成要素を準備します。 GitLabユーザー作成 ソースコード用プロジェクトの作成 デプロイ用プロジェクトの作成 OpenShift側のNamespaceと権限設定 Gatekeeperのポリシー設定 1. GitLabユーザー作成 管理者アカウントでGitLabにログインし、プロジェクト管理用ユーザーを作成します。 今回使用するプロジェクトのネームスペースはここで作成したユーザー名を指定します。 続いて、作成したプロジェクト管理用ユーザー(devsecops-user)にSSHキーを登録し、Gitでのアクセスを確認します。 作成したプロジェクト管理用ユーザーでログインし、サイドメニューからアバターアイコンを選択→[プロファイルを編集]をクリックして、ユーザー設定画面に移動します。 ユーザー設定画面のサイドメニューで[SSHキー]を選択し、このユーザー用に作成した公開鍵を登録します。 例:SSHキー生成とGitLab接続確認 $ ssh-keygen -t rsa -b 4096 -C "devsecops-user@gitlab.local" $ ssh -T git@gitlab-private.example.local 2. ソースコード用プロジェクト 先ほど作成したプロジェクト管理用ユーザーでログインし、GitLabで新規プロジェクトを作成します。 このプロジェクトはイメージのビルドとレジストリへのイメージ保存を担当します。 プロジェクト作成の詳細な手順は弊社ブログ記事 Git & GitLab 入門 (7) ~Git マスターへの道~「GitLabのプロジェクトについて」 | SIOS Tech. Lab をご参照ください。 続いて、作成したビルド用プロジェクト内でmain と develop ブランチを用いし、保護ブランチの設定を行います。 ブランチの保護設定を行うことで、mainブランチ及びdevelopブランチへの直接pushを防止し、パイプラインの誤動作を防止します。 ブランチ保護設定手順の詳細につきましても、弊社ブログ記事 Git & GitLab 入門 (7) ~Git マスターへの道~「GitLabのプロジェクトについて」 | SIOS Tech. Lab に記載しておりますので、ご参考になれば幸いです。 任意の開発者用ユーザーを作成し、プロジェクトにDeveloper権限で追加します。このユーザーはプロジェクト内でコードをコミットしたり、パイプラインを操作するために利用します。 プロジェクトにユーザーを招待する方法や主要なユーザー権限につきましては、 Git & GitLab 入門 (7) ~Git マスターへの道~「GitLabのプロジェクトについて」 | SIOS Tech. Lab に記載しておりますのでご参照ください。 プロジェクトに追加した開発用ユーザーでログインし、サンプルのアプリコードをリポジトリのfeatureブランチにpushし、管理を開始します。 アプリのベースイメージ(nginx:latestなど)をGitLab Container Registryにpushします。 ※この記事では、OpenShiftの環境を使用しているため、コンテナ管理ツールとしてPodmanを利用しています。Dockerを利用している環境ではpodman→dockerに読み替えてください。 $ podman login registry.gitlab.local.example.com $ podman pull nginx:latest $ podman tag nginx:latest registry.gitlab.local.example.com/devsecops-user/devsecops-build-project/nginx:latest $ podman push registry.gitlab.local.example.com/devsecops-user/devsecops-build-project/nginx:latest 参考: Git & GitLab 入門 (7) ~Git マスターへの道~「GitLabのプロジェクトについて」 | SIOS Tech. Lab 3. デプロイ用プロジェクト プロジェクト管理用ユーザーでGitLabにログインし、今度はデプロイ用のGitLabプロジェクトを新規作成します。 このプロジェクトはレジストリのイメージを参照し、Helmを用いてOpenShiftにデプロイする役割を担います。 ビルド用プロジェクトを作成した時と同様に、mainとdevelopブランチに保護設定を行います。 今回はデプロイ手段としてHelmチャートを利用するため、このプロジェクトのレジストリにHelmが利用可能なコンテナイメージを格納します。 ※この記事では、OpenShiftの環境を使用しているため、コンテナ管理ツールとしてPodmanを利用しています。Dockerを利用している環境ではpodman→dockerに読み替えてください。 $ podman login registry.gitlab.local.example.com $ podman pull docker.io/alpine/helm:3 $ podman tag docker.io/alpine/helm:3 \   registry.gitlab.local.example.com/root/test-project/helm:3 $ podman push registry.gitlab.local.example.com/root/test-project/helm:3 デプロイ用プロジェクトのレジストリにHelmイメージを格納しておくと、パイプライン内で実行されるジョブPodのイメージを指定できます。この指定は、パイプライン定義ファイル(.gitlab-ci.yml)のimageプロパティで行います。 .default_deploy: &default_deploy   stage: deploy   image: registry.gitlab.local.example.com/devsecops-user/devsecops-deploy-project/helm:3   before_script:     - set -euo pipefail     - helm version     - |       if [ -n "${K8S_NAMESPACE:-}" ]; then         HELM_NS_ARG="-n ${K8S_NAMESPACE}"       else         echo "K8S_NAMESPACE variable not provided. Helm will use the current context's namespace."         HELM_NS_ARG=""       fi     - helm dependency update "$HELM_CHART_DIR" || true 今回使用するデプロイ用パイプラインは、ブランチに応じてデプロイ先のネームスペースを決定します。 たとえば、developブランチにマージした時はdevsecops-developネームスペースにアプリをデプロイし、mainブランチにマージした時はdevsecops-productionネームスペースにアプリをデプロイするなどの制御を行います。 deploy_develop:   <<: *default_deploy   tags:     - devsecops-runner   variables:     <<: *common_vars     VALUES_ENV: "deploy/Config/develop-values.yaml"     K8S_NAMESPACE: "$DEPLOY_PROJECT_NAME_DEVELOP"   rules:     - if: '$CI_COMMIT_BRANCH == "develop" && $CI_PIPELINE_SOURCE == "push"'   environment: { name: develop, deployment_tier: development }   script:     - |       set -euo pipefail       : "${HELM_RELEASE:=devsecops-nginx}"       : "${HELM_CHART_DIR:=deploy/devsecops-nginx-chart}"       : "${VALUES_COMMON:=deploy/devsecops-nginx-chart/values.yaml}"       : "${VALUES_ENV:?VALUES_ENV must be set}"       test -f "${HELM_CHART_DIR}/Chart.yaml" || { echo "Chart.yaml not found under ${HELM_CHART_DIR}"; exit 1; }       echo "[RUN] helm upgrade --install ${HELM_RELEASE} ${HELM_CHART_DIR} ${HELM_NS_ARG} -f ${VALUES_COMMON} -f ${VALUES_ENV}"       helm upgrade --install "${HELM_RELEASE}" "${HELM_CHART_DIR}" ${HELM_NS_ARG} -f "${VALUES_COMMON}" -f "${VALUES_ENV}" deploy_production:   <<: *default_deploy   tags:     - devsecops-runner   variables:     <<: *common_vars     VALUES_ENV: "deploy/Config/product-values.yaml"     K8S_NAMESPACE: "$DEPLOY_PROJECT_NAME_PRODUCTION"   rules:     - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"'       allow_failure: false   environment: { name: production, deployment_tier: production }   script:     - |       set -euo pipefail       : "${HELM_RELEASE:=devsecops-nginx}"       : "${HELM_CHART_DIR:=deploy/devsecops-nginx-chart}"       : "${VALUES_COMMON:=deploy/devsecops-nginx-chart/values.yaml}"       : "${VALUES_ENV:?VALUES_ENV must be set}"       test -f "${HELM_CHART_DIR}/Chart.yaml" || { echo "Chart.yaml not found under ${HELM_CHART_DIR}"; exit 1; }       echo "[RUN] helm upgrade --install ${HELM_RELEASE} ${HELM_CHART_DIR} ${HELM_NS_ARG} -f ${VALUES_COMMON} -f ${VALUES_ENV}"       helm upgrade --install "${HELM_RELEASE}" "${HELM_CHART_DIR}" ${HELM_NS_ARG} -f "${VALUES_COMMON}" -f "${VALUES_ENV}" デプロイ用パイプラインが読み取れるCI/CD変数を登録します。 プロジェクト画面のサイドメニューから[設定] > [CI/CD]を選択し、[変数]のメニューを展開します。 [変数を追加]をクリックすると、CI/CDパイプラインが利用可能な環境変数を定義することができます。今回の例では、環境別のネームスペース名であるDEPLOY_PROJECT_NAME_DEVELOPとDEPLOY_PROJECT_NAME_PRODUCTIONを定義しています。他にも外部サービスのAPIキーなどを登録するなどの利用が可能です。 上記の作業が完了した後、デプロイ用のHelmチャートやマニフェストをfeatureブランチにpushします。 4. OpenShift設定 開発用 (develop) と本番用 (production) のNamespaceを作成し、ラベルを付与します。 ※tagのenvにはdevやprodなどデプロイ先の環境名を指定しています。 $ oc create namespace <namespace> $ oc label namespace <namespace> tag=<env> GitLab Runner用のServiceAccountを作成し、必要なRBAC権限とSCCを付与します。 開発用 (develop) と本番用 (production) のNamespaceのGitLab Runner用のServiceAccountに必要なRBAC権限を付与 GitLab Container RegistryへのPull SecretをNamespaceに登録します。 自己署名証明書を利用している場合はCA証明書をSecretとして登録します。 開発用 (develop) と本番用 (production) のNamespaceのdefault ServiceAccountにanyuidのSCCを付与します。 GitLab Runner用のNamespaceのServiceAccountにデプロイ先namespaceでのedit権限を付与します。 5. Gatekeeper設定 必要なConstraintTemplateを作成します(例:イメージタグに特定文字列を含める、Namespaceとラベルが一致していることなど)。 今回作成したポリシールールは こちらのリポジトリ をご参照ください。 開発環境、本番環境それぞれを対象としたConstraintsを作成します。 oc get コマンドでConstraintTemplateとConstraintsが正しく反映されていることを確認します。 参考: OPA/Gatekeeperで始める安心OpenShift運用:設定編 まとめ ここまでで、GitLabのビルド・デプロイ用プロジェクト、OpenShiftのNamespace設定、Gatekeeperのポリシー適用といった要素が揃い、セキュリティを組み込んだCI/CD基盤のモデルケースが完成しました。これにより、ソースコードの変更がパイプラインを通じて自動的にビルド・デプロイされるだけでなく、Gatekeeperによるポリシー検証によって不適切なリソースの作成を未然に防ぐことが可能になります。 本記事で紹介した構成は、高いセキュリティ要件が求められるシステムにおいても有効なアプローチです。次回の記事では、この環境を活用して実際のパイプライン実行からポリシー違反検知までの一連の流れをデモンストレーションします。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post DevSecOps実践ガイド:CI/CD環境の構築編 first appeared on SIOS Tech. Lab .
はじめに 前回 までは、GitとGitLabの具体的な機能や操作方法を入門者向けに解説してきました。 今回は、GitLabの根幹となる「DevSecOps」という考え方を中心に解説します。近年のソフトウェア開発では、開発のスピードを上げつつ、セキュリティを確保することが不可欠です。この相反する課題を解決するために必要なアプローチが「DevSecOps」です。 このDevSecOpsをGitLabがどのように実現しているのか、そしてそれがどのようなメリットを生み出すのかを、公式事例を交えて具体的に解説します。 DevOpsとは? まず、DevSecOpsを理解するために、その土台となるDevOpsについて解説します。 DevOpsは、開発チーム(Development)と運用チーム(Operations)が連携し、アプリケーションのビルドからテスト、デプロイ、リリースまでのプロセスを自動化し、高速化する取り組みです。これにより、新しい機能を素早く提供し、顧客のフィードバックに迅速に対応することが可能になります。 DevSecOpsとは? DevSecOpsとは、DevOpsの迅速な開発・運用プロセスにセキュリティを統合することで、スピードと安全性を両立する手法です。 従来の「開発の後にセキュリティチェックを行う」アプローチではなく、開発ライフサイクルの各段階にセキュリティを組み込む点が特徴です。 開発の最終段階で脆弱性が発見されると、その修正には時間とコストがかかり、リリースの遅延につながります。DevSecOpsは、このような手戻りをなくすために、早い段階で問題を検知し、小さな修正で済ませることを目指します。これにより、開発のスピードを保ちつつ、コスト削減と安全性の向上を同時に実現できます。 詳細については以下の記事で解説していますので、ご参照ください。 DevSecOpsとは?安全性とスピードを両立する開発手法 | SIOS Tech. Lab GitLabでのDevSecOpsの扱い GitLabは、DevOpsの統合プラットフォームであるため、DevSecOpsを体現したツールです。 GitLabはCI/CDパイプラインにセキュリティスキャン機能を組み込むことが可能です。開発者は、追加のツールや設定をすることなく、以下の代表的なセキュリティ機能をCI/CDパイプラインに含めることができます。 静的アプリケーションセキュリティテスト(SAST):コードをビルドする前に、ソースコードに存在する脆弱性を自動で検知します。 認証情報検知(Secret Detection):コード内に誤ってコミットされたAPIキーやパスワードなどの機密情報を自動で検出します。 依存関係スキャン(Dependency Scanning):プロジェクトが使用しているライブラリやフレームワークに既知の脆弱性がないかをチェックします。 これらのスキャン結果は、マージリクエスト画面にCI/CDパイプラインの実行結果として直接表示されるため、レビュー時にコード品質とセキュリティの両方を一度に確認できます。 参考: Git & GitLab 入門 (6) ~Git マスターへの道~「GitLabの画面説明とよく利用される機能説明」 GitLab公式で提示しているDevSecOpsの事例について GitLabのDevSecOps機能は、規模を問わず多くの企業で成果を上げています。ここでは、GitLabの公式事例からそのメリットを具体的に見てみましょう。 参考: https://about.gitlab.com/ja-jp/customers/ エンタープライズ事例:Hilti社(デプロイ時間の短縮) 建設業界の大手であるHiltiは、以前、ソフトウェア開発の一部を外部に委託しており、社内でのコード管理やCI/CD体制が十分に整っていませんでした。そのため、バグや脆弱性への対応が後手に回り、セキュリティ上のリスクやコード品質の低下が課題となっていました。 これらの課題を解決し、セキュリティスキャンを最優先にソフトウェア開発を社内化するため、統合のしやすさ、SCM (Source Code Management)、豊富なSAST/DAST等のセキュリティ機能を理由にGitLab Ultimateを採用しました。 GitLab導入の具体的な成果として、デプロイ時間が平均3時間からわずか15分に短縮されました。これは、以下が大きな要因です。 開発・テストチームがコードを管理し、脆弱性を事前に発見できるようになった フィードバックループが6日から3日に短縮されたこと コードチェック頻度が3か月6回から週2回に増加 これにより、Hiltiはセキュリティ、コード品質、開発効率、チームコラボレーションを大幅に向上させることができました。 参考: https://about.gitlab.com/customers/hilti/ ミッドマーケット事例:Carfax社(脆弱性の早期発見) 自動車履歴データベースを提供するCarfaxは、以前、複数のDevOpsツールチェーンの維持管理をするため、多くの時間やコストがかかっていました。さらに、開発ライフサイクル後半の手動による脆弱性スキャンで問題が発覚することが多く、迅速な修正が難しい状況でした。 より早い段階でセキュリティリスクを検知したいという課題から、GitLabのDevSecOpsプラットフォームを採用しました。Carfaxは導入後6ヶ月以内に、コードをGitLabに移し、GitLabのセキュリティスキャンを活用し始めました。 GitLabの自動セキュリティ機能(依存関係スキャン、コンテナスキャン、シークレット検出など)を導入することで、Carfaxは1年間で脆弱性の約3分の1を開発ライフサイクルのかなり早い段階で発見できるようになりました。これにより、開発チーム全体がソフトウェアライフサイクルの最も早い段階からセキュリティを考慮する「シフトレフト」を実現し、問題の修正にかかる時間とコストを大幅に削減し、セキュリティを向上させました。 参考: https://about.gitlab.com/customers/carfax/ 中小企業(SMB)事例:Jasper Solutions社(オールインワンの利点) 政府・民間向けのソフトウェア開発を行うJasper Solutionsは、以前、 複数の個別ツールを組み合わせた開発パイプラインを利用していましたが、個々のツールのバージョンアップが原因でパイプラインが頻繁に機能しなくなり、開発チームは顧客向けのコード開発よりもその修正に多くのリソースを割かなければなりませんでした。 こうした運用負荷を根本から解決するため、GitLabをCI/CD、SCMを統合した「オールインワン」プラットフォームとして採用しました。 GitLabの「オールインワン」プラットフォームにより、パイプラインの破損がほぼなくなり、単一のアップグレードでパイプライン全体が常に最新の状態に保たれるため、開発チームはアプリケーション開発に集中できるようになりました。この統合によって、以下の具体的なメリットが生まれています。 1製品あたり年間平均約350人時の作業時間を削減 個別のツールを維持管理する費用と比較して年間33〜37%のコスト削減 サイクルタイムが30%短縮され、デプロイ頻度が25%向上 Jasper Solutionsは、GitLabの「オールインワン」の利点を最大限に活用することで、複数のツールチェーンの維持管理から解放され、開発への集中と運用コストの削減を同時に実現できました。 参考: https://about.gitlab.com/customers/jasper-solutions/ GitLabのDevSecOpsを導入することによって、Hilti社ではデプロイ時間の短縮、Carfax社では脆弱性の早期発見、Jasper Solutions社では運用コスト削減と安定化が実現されました。 事例 改善効果 Hilti社 デプロイ時間の短縮(平均3時間から15分) Carfax社 脆弱性の早期発見(約3分の1) Jasper Solutions社 運用コスト削減と安定化(年間33〜37%のコスト削減) まとめ 今回は、GitLabがCI/CDパイプラインにセキュリティスキャン機能を統合することで、開発スピードと安全性を両立する「DevSecOps」という手法を実現していることを解説しました。 そして、GitLabが実際の企業事例(Hilti、Carfax、Jasper Solutions)でどのような具体的な成果(デプロイ時間の短縮、脆弱性の早期発見、運用コストの削減など)を生み出しているかを具体的に見てきました。 これまで学んだGitLabの基本操作を踏まえ、次は実際にDevSecOpsを体験できる環境を構築する方法をご紹介します。 参考文献 https://about.gitlab.com/ja-jp/customers/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Git & GitLab 入門 (10) ~Git マスターへの道~「GitLabでDevSecOps」 first appeared on SIOS Tech. Lab .
/br今号では、nftables について、その仕組みや設定方法について説明します! nftables とは nltables とはパケットフィルタリング (通過するパケットの IPアドレス、プロトコル、ポート番号などをフィルタリング設定に基づいてチェックし、通信を許可・拒否を判断すること) ツールの名称です。カーネル 3.13 (RHEL だとバージョン 8系) から導入されました。 従来は iptables、ip6tables、arptables、ebtables といった複数のツールを使い分けてフィルタリング設定をする必要がありましたが、これらのツールを 1つの nft コマンド に統合し、より管理しやすくなりました。 nftables は従来のツールと比較して構文がシンプルかつ柔軟に設定ができるようになっています。 なお、nftables について過去に下記の記事でもご紹介しています。2019年の記事ということもあり、前回説明しきれなかった部分も含めてご紹介できればと思います。 ※内容が重複してしまう部分もあります。ご了承ください。 https://tech-lab.sios.jp/archives/16930#teburuno_she_ding フィルタリング設定の全体的な構造 nftables では、フィルタリング設定のことを ルールセット と呼びます。 ルールセットは、inet、ip、ip6 などのアドレスファミリごとに作成できる テーブル 、さらにテーブル内にフィルタリングのルールをひとまとめに管理するための チェーン 、そしてチェーン内で具体的なルール設定を行うための ルール が含まれる構造になっています。 基本の書式 nft コマンド の基本的な使用方法をご説明します。 ルールセットの追加 nftables によるフィルタリング設定は、 ①テーブル、②チェーン、③ルール 、という順序で行なっていきます。 テーブルの追加 テーブルを新しく追加するには nft add table コマンド を使用します。 例1:inet ファミリのテーブルを作成 # nft add table inet table1 例2:ip4 ファミリのテーブルを作成 # nft add table ip table2 チェーンの追加 チェーンを新しく追加するには nft add chain コマンド を使用します。 例1:table1 テーブルに新しいチェーンを作成 # nft add chain inet table1 chain1 { type filter hook input priority 0 \; } ※ “{}” 内で指定する type、hook、priority に指定可能な値については、過去にご紹介した記事でも説明しています。 (ブログより抜粋) —– ・type には、filter、route、nat のいずれかを設定します。 ・hook には、prerouting、input、forward、output、postrouting のいずれかを設定します。 ・priority には、チェインの優先度 (整数値) を設定します。  値が小さいほど、優先度は高くなります。また、負の値を設定することもできます。 —– ルールの追加 ルールを新しく追加するには nft add rule コマンド を使用します。 例1:table1 テーブル内の chain1 に、22 番ポート (SSH) による外部アクセスを許可するルールを作成 # nft add rule inet table1 chain1 tcp dport 22 accept 例2:table1 テーブル内の chain1 に,、80 番ポート (HTTP) による外部アクセスを許可するルールを作成 # nft add rule inet table1 chain1 tcp dport 80 accept ルールセットの表示 ルールセットの内容を表示するには nft list ruleset コマンド を使用します。 # nft list ruleset table inet table1 { chain chain1 { type filter hook input priority filter; policy accept; tcp dport 22 accept tcp dport 80 accept } } テーブルの一覧を表示するには nft list tables コマンド を使用します。 ※テーブルの一覧のみ。内容は表示されません # nft list tables table inet table1 特定のチェーンに設定されているルールの内容を表示するには、 nft list chain コマンド を使用します。 # nft list chain inet table1 chain1 table inet table1 { chain chain1 { type filter hook input priority filter; policy accept; tcp dport 22 accept tcp dport 80 accept } } ルールセットの削除 ルールを削除するには nft delete コマンド を使用します。 なお、ルールの削除には各ルールごとに設定されている ハンドル番号 が必須となります。 ハンドル番号の確認方法は、上で説明した nft list chain コマンドに –handle もしくは -a オプションを指定します。 # nft -a list chain inet table1 chain1 table inet table1 { chain chain1 { # handle 1 type filter hook input priority filter; policy accept; tcp dport 22 accept # handle 2 tcp dport 80 accept # handle 3 } } # nft --handle list chain inet table1 chain1 table inet table1 { chain chain1 { # handle 1 type filter hook input priority filter; policy accept; tcp dport 22 accept # handle 2 tcp dport 80 accept # handle 3 } } tcp dport 22 accept の横に handle 2 、 tcp dport 80 accept の横に handle 3 と記載されており、各ルールのハンドル番号を確認することができました。 例えば、上記のうち 22 番ポート (SSH) のルールを削除するには、下記の様に handle 2 と指定します。 # nft delete rule inet table1 chain1 handle 2 次号について 次号では、 nftables の設定例や、知っておくと便利な tips についてご紹介します! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!nftables によるパケットフィルタリング1 first appeared on SIOS Tech. Lab .
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 9/10、IPA (情報処理推進機構) が、「情報セキュリティ白書2025」PDF 版を公開しました。 プレス発表「情報セキュリティ白書2025」PDF版の公開 https://www.ipa.go.jp/pressrelease/2025/press20250910.html 9/16、LPI-Japanは Linux の学習教材の最新版である「Linuxシステム管理標準教科書 バージョン2.0.0」を公開しました。 PDF版と ePub版は無償で提供されています。 LPI-Japan、無償のLinux学習用教材「Linuxシステム管理標準教科書」最新版を公開 https://japan.zdnet.com/article/35238032/ 総務省のサイトより、9/18 に実施された AI セキュリティ分科会の資料が公開されました。 総務省 – AIセキュリティ分科会(第1回) https://www.soumu.go.jp/main_sosiki/kenkyu/cybersecurity_taskforce/02cyber01_04000001_00321.html ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2025年9月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech. Lab .
はじめに これまで本ブログでは、GitLabをDevSecOpsのための開発プラットフォームとして利用する際に必要となる主要機能(コンテナレジストリやCI/CD)について紹介してきました。今回はその基盤をより安定して運用するために欠かせない冗長化構成について紹介します。 概要 GitLabを構成するコンポーネントとして以下のものがあります: GitLab Rails UIの提供やAPIの管理を行うGitLabの中核を成すウェブアプリケーションです Consul GitLabの各コンポーネントのサービスディスカバリーとヘルスチェックを行うコンポーネントです Database(PostgreSQL) GitLabの主要データ(プロジェクト、ユーザーなど)を保存するデータベースです Sidekiq GitLabのバックグラウンドジョブを非同期で処理するためのコンポーネントです Redis GitLabの一時的なデータ(キャッシュ、ジョブキューなど)を保存する高速なインメモリデータストアです Gitaly Cluster Gitリポジトリの読み書きを行うコンポーネントです 今回は以下のようなGitLabの構成例( 例:最大 1000 RPS または 50,000 ユーザー )を参考にして各コンポーネントの冗長化について説明します。 GitLabの構成例(引用: 最大 1000 RPS または 50,000 ユーザー ) 各コンポーネントの冗長化 GitLab Rails GitLab Railsの冗長化 GitLab RailsはGitLabのアプリケーションサーバーです。想定されるアクセスユーザーに合わせてノードを水平スケールする必要があります。(参考: https://docs.gitlab.com/administration/reference_architectures/ ) アプリケーションサーバーは多数のユーザーからのリクエストを処理する必要があります。また、アプリケーションサーバーから内部の各種コンポーネントに多数のリクエストが送られます。そのため、GitLab Railsの冗長化には外部ロードバランサーと内部ロードバランサーが使われます。 外部ロードバランサーはGitLabへアクセスする際の外部からのSSH、HTTPS通信のトラフィックを分散させます。TLS終端をロードバランサーによって行うことが可能です。 内部ロードバランサーはPgBouncerやGitaly Cluster (Praefect)への接続などの内部コンポーネント同士の通信を仲介して、負荷を分散します。 Consul Consulの冗長化 Consulは各コンポーネントの監視を行い、サービスディスカバリーとヘルスチェックを行うコンポーネントです。GitLabの各コンポーネント同士の接続の手伝いをします。 クォーラム(クラスターが正常に機能する最小台数)を維持するために、3ノード以上の奇数ノードにConsulをデプロイする必要があります。 Database(PostgreSQL) Database(PostgreSQL)の冗長化 GitLabでは主要データ(プロジェクト、ユーザーなど)を保存するデータベースとしてPostgreSQLが利用されます。 GitLabのPostgreSQLでは単一障害点を回避するためにプライマリDBとセカンダリDBの2種類が用意されます。プライマリDBは実際に利用されるメインのDBで、セカンダリDBはプライマリの内容をリアルタイムで複製している読み取り専用の予備のDBです。 PgBouncerは各コンポーネントがPostgreSQLのDBに接続を行う際に仲介をして、DB本体への負荷を軽減させるコンポーネントです。PgBouncerがないとGitLabへの接続制限によって、エラーが出たり処理速度が低下します。PgBouncer自身は内部ロードバランサーによって負荷分散されます。 また、PatroniというPostgreSQLのHAクラスタを管理するツールを用いることによってプライマリDBに障害が起きた場合、セカンダリDBをプライマリに昇格する処理が自動的に行われます。 Sidekiq Sidekiqの冗長化 SidekiqはGitLabの様々なバックグラウンドジョブ(メール送信、CIジョブなど)を処理するコンポーネントです。 Sidekiqのキューにジョブが追加されていくと、あるコンポーネントで処理が低下した場合、連鎖的にすべてのジョブの速度が低下する可能性があります。そのような場合の対策として、以下のようなものがあります。 複数インスタンスを立ち上げて処理能力を増やす ジョブを小さな単位に分割する ジョブのキューを最適化する 上記に示す通りSidekiqの冗長化は単純に水平スケールするだけでなく、ジョブキューの設計を適切に行うことが重要になります。 Sidekiqはログを見ることによってジョブの実行時間や実行回数を視覚的に確認することが可能です。その結果をSidekiqのキューの設計に反映させて、継続的にキューの最適化を行う必要があります。 Sidekiqのログ(引用: GitLabの負荷分散 ) Redis Redisの冗長化 RedisはGitLabで高速処理が求められる様々な一時的なデータを保存するために利用されます。PostgreSQLと同じくプライマリとセカンダリに別れていますが、Redisのセカンダリは読み取りができません。 ジョブキューやユーザーセッションの状態の情報など、失われるとGitLabの機能が停止するような情報はRedis Persisetentに保存され、Cacheやログなどの失われてもGitLabが動作できるような情報はRedis Cacheに保存されます。 Redis Sentinelというコンポーネントによって、Redisのプライマリで障害が起きた場合、セカンダリに自動的に切り替えが行われます。 Redisクラスターはクォーラム(クラスターが正常に機能する最小台数)を維持するために、3ノード以上の奇数ノードにデプロイする必要があります。 Gitaly Cluster Gitaly Clusterの冗長化 GitalyはGitリポジトリの読み書きを行うコンポーネントです。 Gitaly ClusterはすべてのGitリポジトリがすべてのGitalyノードに保存され、そのうち一つがプライマリとして動作します。 Gitalyへの接続はすべてPraefectというGitaly Clusterのリクエストをルーティングするコンポーネントを経由します。これによってGitalyノードで障害が起きた場合、自動的にフェイルオーバーします。また、PraefectはTLSの接続をサポートしています。 Praefect自身は内部ロードバランサーによって負荷分散されます。また、クォーラム(クラスターが正常に機能する最小台数)を維持するために、3ノード以上の奇数ノードにデプロイする必要があります。 PraefectにはGitaly Clusterのステータスを保存する独自のDB(Praefect PostgreSQL)が必要になります。GitLabのLinuxパッケージで構築する場合、非HA構成のDBになります。高可用性を保ちたい場合は外部の冗長化されたPostgreSQLが必要になります。 終わりに 今回はGitLabの各コンポーネントの冗長化について解説しました。セキュアで継続的な開発環境を実現するための土台として、冗長化の考え方を理解しておくことはDevSecOpsの観点でも重要です。今回示した例は1000RPSまたは50,000ユーザーを想定した大規模な環境です。各々のユースケースに適したGitLabの構成を設計し、その環境規模に応じてどのコンポーネントを冗長化するべきか判断する必要があります。今回の記事がその判断材料の助力になれば幸いです。 参考 GitLabコンポーネントリスト https://docs.gitlab.com/development/architecture/#component-list GitLabリファレンスアーキテクチャ https://docs.gitlab.com/administration/reference_architectures/ 例:最大 1000 RPS または 50,000 ユーザー https://docs.gitlab.com/administration/reference_architectures/50k_users/ マルチノードGitLab向けロードバランサー https://docs.gitlab.com/administration/load_balancer/ GitLabの負荷分散 https://docs.gitlab.com/development/scalability データベース負荷分散 https://docs.gitlab.com/administration/postgresql/database_load_balancing/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post GitLabの冗長化構成を徹底解説:安定運用のための実践ガイド first appeared on SIOS Tech. Lab .
はじめに 前回の記事では、2回にわたりGitLab CI/CDの基本的なパイプライン作成方法 を解説しました。ジョブの定義からステージの構成まで、一通りの流れを実際に試しながら理解できたと思います。 しかし、実際にチーム開発を進めていくと、パイプラインの定義ファイルである.gitlab-ci.ymlがすぐに肥大化しがちです。 同じ処理を複数のジョブに書いてしまう プロジェクトごとに似たような CI 定義をコピペして使い回す こうした状態になると、修正や共通化が難しくなり、運用コストが増えてしまいます。 そこで今回の記事では、GitLab CI/CDが用意している include と extends の仕組みに注目します。これらを活用することで、設定を整理し、再利用しやすい形に整えることができます。 小さな検証を通して、それぞれの機能がどのように役立つかを紹介していきます。 include機能:外部ファイルのインポート includeは、別ファイルに書かれたCI定義を取り込む機能です。別のプロジェクトにあるファイルを読み込めるのが大きな特徴です。今回の検証では、テスト用にGitLab上で 2 つのプロジェクトを用意し、一方のプロジェクトにあるパイプライン定義を、もう一方のプロジェクトからincludeで読み込む形を確認しました。 検証環境 メインプロジェクト:runner-test-project-1 .gitlab-ci.yml(実際にパイプラインを実行する定義ファイル) インポート用プロジェクト:runner-test-project-2 ci/shared.yml(他のプロジェクトから取り込んで使うためのジョブ定義ファイル) 設定例(実行側) # runner-test-project-1/.gitlab-ci.yml variables:   FROM_PROJECT: "overridden-in-runner-test-project-1" include:   - project: "group/runner-test-project-2"     ref: "main"     file: "/ci/shared.yml" stages: [test] check-local:   stage: test   script:     - echo "FROM_PROJECT=${FROM_PROJECT}" 設定例(includeされる側) # runner-test-project-2/ci/shared.yml project-job:   stage: test   variables:     FROM_PROJECT: "default-in-provider-project"   script:     - echo "FROM_PROJECT=${FROM_PROJECT}" 実行結果 check-local(ローカルジョブ)と project-job(外部ジョブ)がどちらもパイプラインに表示される すべてのジョブが成功 FROM_PROJECT=overridden-in-runner-test-project-1 が出力され、実行側の変数が優先されることを確認 ポイント 変数の上書き :同じ名前の変数が複数定義されている場合、最終的にはメインの.gitlab-ci.ymlファイルで定義された値が優先されます。外部ファイル側はデフォルト値を置き、環境依存の値はメイン側で上書きするのがベストです。 権限 :実行するユーザーが参照先リポジトリを読む権限を持っている必要があります。安定運用のためには、参照元・参照先を同じグループ内にまとめておくとよいでしょう。 ref の固定 :main を参照すると、外部ファイルの変更が即座に反映されてしまうため、安定性を重視するなら、タグやリリースブランチを指定するのがおすすめです。 参考: Use CI/CD configuration from other files | GitLab Docs extends機能:共通設定の継承 extendsは、ジョブごとに共通する設定をテンプレートとしてまとめ、そこから継承できる仕組みです。同じ処理や変数を繰り返し記述せずに済むのが大きな特徴です。今回の検証では、共通設定を.default-templateとして定義し、job_aではそのまま継承、job_bでは一部の変数を上書きする形を確認しました。 検証環境 任意のプロジェクトに extends-gitlab-ci.yaml を作成し、次の内容を記述しました。 設定例 stages: [test] # 共通設定(テンプレート) .default-template:   stage: test   image: registry.gitlab.local.example.com/root/registry-project/alpine:latest   tags:     - devsecops-runner   before_script:     - echo "BEFORE(from base) run common setup"   variables:     BASE_VAR: from-base     OVERRIDE_ME: from-base # 継承のみ(上書きなし) job_a:   extends: .default-template   script:     - echo "A BASE_VAR=$BASE_VAR OVERRIDE_ME=$OVERRIDE_ME"     - echo "A IMAGE=$(cat /etc/alpine-release 2>/dev/null || echo unknown)" # 一部上書き(variables を上書き) job_b:   extends: .default-template   variables:     OVERRIDE_ME: from-job-b   script:     - echo "B BASE_VAR=$BASE_VAR OVERRIDE_ME=$OVERRIDE_ME" 実行結果 すべてのジョブが成功 job_a BASE_VAR=from-base OVERRIDE_ME=from-base before_script の “BEFORE(from base) run common setup” が実行され、image も alpine:latest が利用されている job_b → 変数 OVERRIDE_ME はジョブ側の値で上書き、BASE_VAR や before_script はテンプレートの値がそのまま反映されている BASE_VAR=from-base(テンプレートのまま) OVERRIDE_ME=from-job-b(ジョブ側の値で上書き) before_script と image はテンプレートの設定が適用されている ポイント 共通化のメリット :before_script や変数をテンプレートにまとめることで、修正が必要になった際に1箇所を直すだけで全ジョブに反映できます。結果として、ジョブテンプレートの管理や保守がシンプルになり、影響範囲も明確に把握できます。 変数の上書き :テンプレートとジョブの両方に同じキーが定義されている場合、ジョブで定義された値が優先されます。テンプレートは共通の値を設定し、必要に応じてジョブ側で上書きするのが基本的な使い方です。 参考: Optimize GitLab CI/CD configuration files まとめ includeを使うと、外部ファイルを取り込んで 共通ジョブを複数のプロジェクトで再利用できます。 extendsを使うと、共通設定をテンプレート化してジョブごとの差分だけを簡潔に記述できます。 どちらの機能も、複雑化しやすい .gitlab-ci.yml を整理し、変更や保守を効率化するために欠かせない仕組みです。 チームやプロジェクトが大きくなるほど、パイプラインの管理は難しくなります。include とextendsを活用すれば、CI/CD 設定をシンプルかつ再利用性の高い形に整え、大規模な開発環境でも安定して運用できる基盤を作ることができます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post GitLab CI/CD 実践[応用編]:共通設定と外部ファイルの利用 first appeared on SIOS Tech. Lab .