TECH PLAY

電通総研

電通総研 の技術ブログ

822

みなさんこんにちは、 電通国際情報サービス (ISID)コーポレート本部 システム推進部の佐藤太一です。 このエントリでは Google Dataflowを使ったデータ分析パイプライン構築において中心的な API の使い方について説明します。 Google Dataflowとはなにか Dataflowの開発環境構築 GradleによるDataflowプロジェクトの作り方 Apache Beamの基礎 Pipelineについて PCollectionについて ParDoを使った逐次処理の書き方 Dataflowによるユニットテストの書き方 フィルター フィルターのテスト 値の増幅処理 増幅処理のテスト PCollectionの分岐 PCollectionの分岐をテストする まとめ Google Dataflowとはなにか Google DataflowはいわゆるExtract/Transform/Load(ETL)ツールの一種です。 Apache Beam という バッチ処理 基盤を GCP の分散処理環境で動かしてくれます。 Apache Beam自体は、 Apache Flink や Apache Spark 、 Hazelcast Jet といったオンプレミスで動作する実行環境を利用することもできます。 Apache Beamでは、 Java や Python 、Goといった言語で処理を記述できますが、今回は Java を使って説明します。 Dataflowの開発環境構築 まずは、Dataflowの開発環境を作っていきましょう。 開発環境として使うマシンには、事前にJava17とGradle7.5以上をインストールしておいてください。 GradleによるDataflowプロジェクトの作り方 最初にプロジェクト全体を格納するための ディレクト リを作成しましょう。 ここからは、この記事内でシェルコマンドを実行するよう説明している部分では、必ずこのルート ディレクト リで実行してください。 作るプロジェクトは、説明のために dataflow-example とします。作った dataflow-example ディレクト リの中で、以下のコマンドを実行して最小限のプロジェクトを作成します。 gradle init --type basic --dsl kotlin --project-name dataflow-example --incubating 最小限とはいえ、Gradle Wrapperとなる シェルスクリプト やgit用の設定ファイルが生成されていますね。 この中から、 build.gradle.kts を以下のように編集します。 plugins { id("java") } group = "com.example.dataflow" version = "0.1.0-SNAPSHOT" java.toolchain { languageVersion.set(JavaLanguageVersion.of(17)) // 1. } repositories { mavenCentral() maven("https://packages.confluent.io/maven/") // 2. } dependencies { var beamVersion = "2.41.0" // 3. var slf4jVersion = "1.7.36" implementation(platform("com.google.cloud:libraries-bom:25.4.0")) // 4. implementation("org.apache.beam:beam-sdks-java-core:${beamVersion}") // 5. implementation("org.apache.beam:beam-sdks-java-io-google-cloud-platform:${beamVersion}") // 5. implementation("org.apache.beam:beam-runners-google-cloud-dataflow-java:${beamVersion}") // 5. implementation("org.apache.commons:commons-csv:1.9.0") implementation("org.slf4j:slf4j-api:${slf4jVersion}") implementation("org.slf4j:slf4j-jdk14:${slf4jVersion}") testImplementation("junit:junit:4.13.2") // 6. testImplementation("org.apache.beam:beam-runners-direct-java:${beamVersion}") // 7. } tasks.withType<JavaCompile>().configureEach { options.encoding = "UTF-8" } このビルド スクリプト で利用する コンパイラ やランタイムのバージョン番号を指定しています。 Gradleを実行している Java ランタイムのバージョンが開発者ごとにズレていても、 コンパイル やテストに使う Java ランタイムは統一できるということです。ビルドの再現性が高まりますので必ず設定しましょう。 この機能を使うと、必要に応じてGradleがビルド済みの JDK を自動的にダウンロードしてくれます。 デフォルトでは Adoptium を使います。 依存ライブラリをダウンロードする先を宣言しています。 最初に指定しているのは Maven のデフォルト アーティファクト リポジトリ である Maven Central Repository です。 二つ目に指定しているのはconfluentが公開している リポジトリ です。これはKafka関連のライブラリで、この リポジトリ 内にしかないものがあるからです。 Apache Beamのバージョンを参照する依存性がいくつかあるので、ここでは変数として切り出しています。 Dataflowを動かすために必要な GCP の SDK に対する依存性を宣言しています。 GradleのPlatform機能 を使っていますね。 Apache Beamに対する依存性を宣言しています。後半の二つは GCP でBeamを動かすために必要な依存性です。 ユニットテスト 用の依存性としてJUnit4を指定しています。 JUnit の最新版はJUnit5系ですが、記事執筆時点において Apache BeamはJUnit5をサポートしていません。cf. JUnit5 support Apache Beam用の ユニットテスト ライブラリに対する依存性を宣言しています。 これでDataflow用のローカルビルド環境の構築は完了です。 Apache Beamの基礎 Apache Beamを理解するなら、まずはPipelineとPCollectionをしっかり理解してください。 他のコンセプトについては、Dataflowのドキュメントを参照してください。 * Apache Beam のプログラミング モデル Pipelineについて Pipelineは複数のステップから構成される処理全体を表すオブジェクトで、データの読み取り処理から始まりフィルターや変換を経て、出力処理までを行います。一つのパイプラインが一つのジョブとなります。 Pipelineを構成する各ステップは、実行環境が必要に応じて分散処理してくれます。つまり、各ステップを効率よく動作させるには、それぞれのステップが全く違ったプロセスの上で非同期に実行されても問題がおきないようにしましょう。 具体的には、処理単位になるデータの独立性をできるかぎり高めるようにします。つまり、 RDB における非正規化を積極的に行うようなデータの持ち方をします。 順序に強い整合性を求める書き方もできますが、そうすると分散処理環境がもつ性能を十分に引き出せません。 PCollectionについて PCollectionはPipelineを流れるデータの集合を表すオブジェクトです。 逐次的に要素を扱えるので Java のCollection Frameworkと似ていますが、PCollectionの API だけではデータの開始と終了を明示的に調べられません。 また、PCollectionに格納されている要素は、分散処理環境内における実行環境の都合で シリアライズ されたりコピーされる可能性があります。つまり、処理に必要な情報は全て要素内に内包する必要があります。 ParDoを使った逐次処理の書き方 基本的な概念が分かった所で本題に入っていきましょう。 最初に作るのは、PCollectionを流れる要素を1:1で変換していく処理です。 この図は四角い枠がPCollectionで、〇が各要素、矢印が処理です。つまり、全体がPipelineとなります。 今回の記事では、全てのコードをテストコードとして実装しますので、以下のように ディレクト リを作成します。 mkdir src/test/java/com/example/dataflow 出来た ディレクト リに CsvFn.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.transforms.DoFn; import java.util.*; public class CsvFn extends DoFn<String, List<String>> { // 1. @ProcessElement // 2. public void processElement(ProcessContext c) throws Exception { // 3. var element = c.element(); // 4. var list = Arrays.asList(element.split(",")); // 5. c.output(list); // 6. } } この処理では、単一の文字列を入力すると、それをカンマ区切りで分割したリストとして後続の処理に引き渡します。 逐次処理を実装する際に使うクラスは DoFn を継承します。 一つ目の型パラメータは、各入力要素を表す型を設定します。ここでは String を設定しています。 二つ目の型パラメータは、各出力要素を表す型を設定します。ここでは List<String> を設定しています。 逐次処理を行うメソッドは @ProcessElement アノテーション を付与します。 逐次処理を行うメソッドのアクセス修飾子は public 、戻り値は void です。送出される例外としては Exception を定義しておきます。 なお、このメソッドの中から例外を送出するとジョブ全体が停止します。 ProcessContext の element メソッドを呼ぶと、 DoFn を継承する際に設定した一番目の型パラメータの変数が得られます。ここでは String 型の変数が得られるわけです。 String の split メソッドを呼びだして得られた配列を List に格納しています。 ProcessContext の output メソッドを呼ぶ際には、 DoFn を継承する際に設定した二番目の型パラメータの変数を渡します。ここでは既に作成済みの list を渡していますね。 Dataflowによる ユニットテスト の書き方 次は、逐次処理を ユニットテスト してみましょう。 CsvFn.java と同じ ディレクト リ内に CsvFnTest.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.testing.*; import org.apache.beam.sdk.transforms.*; import org.junit.*; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.List; @RunWith(JUnit4.class) public class CsvFnTest { static final List<String> values = List.of( "foo,bar,baz", "fo1,ba2,ba3", "ba1,ba2,ba3"); @Rule public TestPipeline pipeline = TestPipeline.create(); // 1. @Test public void testSimplePipeline() throws Exception { var output = pipeline .apply(Create.of(values)) // 2. .apply(ParDo.of(new CsvFn())); // 3. PAssert.that(output).containsInAnyOrder( // 4. List.of("foo", "bar", "baz"), List.of("ba1", "ba2", "ba3"), // 5. List.of("fo1", "ba2", "ba3") ); pipeline.run().waitUntilFinish(); // 6. } } ユニットテスト 用のパイプラインを生成しています。パイプラインを構成するための共通処理があるので @Rule を付与しています。 Create の of メソッドを使って文字列のリストをパイプラインに流せる形に変換しています。ここでは、 List の各要素がパイプラインを流れていきます。 ParDo の of メソッドに先ほど実装した CsvFn を インスタンス 化して渡しています。これによって、パイプラインを流れる各要素ごとに CsvFn の processElement メソッドが呼びだされます。 パイプラインを流れる要素が正しく変換されているか確認するには、 Apache Beamで用意されている専用の PAssert を使います。ここでは containsInAnyOrder メソッドを使ってそれぞれの要素が正しくカンマ区切りで分解されたか確認しています。 values 変数として定義した要素の順序とは違った順序で要素を検証しています。これは、パイプラインを流れる要素の処理順序は保証されておらず、実行環境の都合で任意に入れ替わる可能性があることを意図しています。つまり、 Create の of メソッドで作った要素がそのままの順序で CsvFn の processElement メソッドに入ってくるとは限りません。 TestPipeline の run メソッドを呼びだした上で、さらに waitUntilFinish メソッドを呼んでパイプラインの処理が終わるのを待っています。デバッガで実行する際に注意してほしいのは、この時点で初めてパイプラインの処理が動き始めることです。つまり、 4. の時点では、まだ CsvFn の processElement メソッドは呼びだされません。 フィルター CsvFnでは単純な1:1の変換処理を実装しましたので、次はフィルター処理を実装してみましょう。 フィルター処理として作るのは、指定した長さよりも長い文字列だけを後続の処理に流すフィルターです。 CsvFn.java と同じ ディレクト リ内に FilterFn.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.transforms.DoFn; public class FilterFn extends DoFn<String, String> { // 1. final int size; // 2. public FilterFn(int size) { this.size = size; } @ProcessElement public void processElement(ProcessContext c) { var element = c.element(); if (size < element.length()) { // 3. c.output(element); } } } ここで実装するのはフィルター処理なので、入力と出力の型は同じです。 コンスト ラク タで受け取った長さをメンバ変数として格納しています。 Apache BeamではPCollectionの要素だけでなく、各処理のステップを表すオブジェクトも実行環境の都合で直列化される可能性があります。つまり、メンバ変数としてはSerializableな型(もしくは、Externalizableな型)だけを定義できます。 条件分岐に基づいて ProcessContext の output メソッドを呼びだすかどうかを決めています。 フィルターのテスト では、フィルター処理を ユニットテスト してみましょう。 CsvFn.java と同じ ディレクト リ内に FilterFnTest.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.testing.*; import org.apache.beam.sdk.transforms.*; import org.junit.*; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.List; @RunWith(JUnit4.class) public class FilterFnTest { static final List<String> values = List.of( "alpha", "beta", "gamma"); @Rule public TestPipeline pipeline = TestPipeline.create(); @Test public void testSimplePipeline() throws Exception { var output = pipeline .apply(Create.of(values)) .apply(ParDo.of(new FilterFn(4))); PAssert.that(output).containsInAnyOrder("gamma", "alpha"); pipeline.run().waitUntilFinish(); } } 長さが4文字より大きい単語をフィルターできていますね。 値の増幅処理 次は、一つの入力から複数回の出力を行う処理を実装してみましょう。 増幅処理として作るのは、文字列をカンマ区切りで分割した各要素をそのまま後続に渡す処理です。 CsvFn.java と同じ ディレクト リ内に FlatValuesFn.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.transforms.DoFn; import java.util.Arrays; public class FlatValuesFn extends DoFn<String, String> { // 1. @ProcessElement public void processElement(ProcessContext c) { var element = c.element(); var list = Arrays.asList(element.split(",")); list.forEach(c::output); // 2. } } ここで実装するのは増幅処理なので、入力と出力の型は同じです。 文字列を分割して得られた要素全てについて ProcessContext の ouput メソッドを呼びだしています。 増幅処理のテスト では、増幅処理を ユニットテスト してみましょう。 CsvFn.java と同じ ディレクト リ内に FlatValuesFnTest.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.testing.*; import org.apache.beam.sdk.transforms.*; import org.junit.*; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.List; @RunWith(JUnit4.class) public class FlatValuesFnTest { static final List<String> values = List.of( "foo,bar,baz", "fo1,ba2,ba3", "ba1,ba2,ba3"); @Rule public TestPipeline pipeline = TestPipeline.create(); @Test public void testSimplePipeline() throws Exception { var output = pipeline .apply(Create.of(values)) .apply(ParDo.of(new FlatValuesFn())); PAssert.that(output).containsInAnyOrder( "foo", "bar", "baz", "ba1", "ba2", "ba3", "fo1", "ba2", "ba3" ); pipeline.run().waitUntilFinish(); } } カンマ区切りで3つずつに分割できる要素を3回 FlatValuesFn で処理したので9つの要素が出力されていますね。 PCollectionの分岐 ここまでの処理では、処理の流れであるPCollection自体は1つのまま要素が流れていきました。 しかし、データの1カラム目だけを見て後続の処理を切り替えるといった処理構造を実現したくなることはあります。 ここでは、入力された文字列の1文字目を使って後続の処理を切り替えるためにPCollectionを分岐してみましょう。 CsvFn.java と同じ ディレクト リ内に BranchFn.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.transforms.DoFn; import org.apache.beam.sdk.values.TupleTag; import java.util.*; public class BranchFn extends DoFn<String, List<String>> { static final TupleTag<List<String>> MAIN = new TupleTag<>() { // 1. }; static final TupleTag<List<String>> SUB = new TupleTag<>() { }; @ProcessElement public void processElement(ProcessContext c) { var element = c.element(); var list = Arrays.asList(element.split(",")); if (list.get(0).equals("M")) { c.output(MAIN, list.subList(1, list.size()));       // 2. } else { c.output(SUB, list.subList(1, list.size())); } } } TupleTag は実行環境全体で一意のIDを付与する必要があります。ここでは、ややトリッキーなテクニックを使ってそれを実現しています。コンスト ラク タ呼び出しの後ろについている中括弧 {} によってインナークラスを作成していることがポイントです。実装の詳細が気になる方は是非コードを読んでみてください。 ProcessContext の ouput メソッドを呼びだす際に、 TupleTag を渡しています。これによって各要素にタグ付けをすることで、PCollectionの分岐を実現しているのです。 PCollectionの分岐をテストする では、分岐したPCollectionをどのように扱うのかテストコードで確認してみましょう。 CsvFn.java と同じ ディレクト リ内に BranchFnTest.java というファイルを以下の内容で作成します。 package com.example.dataflow; import org.apache.beam.sdk.testing.*; import org.apache.beam.sdk.transforms.*; import org.apache.beam.sdk.values.TupleTagList; import org.junit.*; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.util.List; @RunWith(JUnit4.class) public class BranchFnTest { static final List<String> values = List.of( "M,foo,bar,baz", "S,fo1,ba2,ba3", "M,ba1,ba2,ba3"); // 1. @Rule public TestPipeline pipeline = TestPipeline.create(); @Test public void testSimplePipeline() throws Exception { var output = pipeline .apply(Create.of(values)) .apply(ParDo.of(new BranchFn()) .withOutputTags(BranchFn.MAIN, TupleTagList.of(List.of(BranchFn.SUB))) // 2. ); PAssert.that(output.get(BranchFn.MAIN)).containsInAnyOrder( // 3. List.of("foo", "bar", "baz"), List.of("ba1", "ba2", "ba3") ); PAssert.that(output.get(BranchFn.SUB)).containsInAnyOrder( // 4. List.of("fo1", "ba2", "ba3") ); pipeline.run().waitUntilFinish(); } } テストデータとして、各要素の先頭に分岐の条件となる M や S を配置しています。 ParDo の of メソッドを呼びだして得られた変数に対して、 withOutputTags を呼びだすことでこのパイプラインが分岐することを宣言しています。 ここでは二つに分岐していますが、三つや四つ、それよりも多くのPCollectionに分岐できます。 分岐されたパイプラインから MAIN でタグ付けされた PCollection を取り出しています。 1. では文字列の先頭が M になっているものがこれにあたります。 分岐されたパイプラインから SUB でタグ付けされた PCollection を取り出しています。 1. では文字列の先頭が S になっているものがこれにあたります。 まとめ Apache Beamを使った バッチ処理 を書く上で最も汎用性の高い ParDo を使ったスタイルをいくつか紹介しました。 今日紹介したスタイルは、それぞれ専用の API が用意されていますが、必要に応じて API を覚えなおすのはやや面倒です。 例えば、型を1:1で変換するなら、 MapElements という専用の API があります。フィルターしたいなら Filter があります。 ParDo には、この記事では紹介しきれなかった便利な機能が他にもありますので是非試してみてください。 Google Dataflowは非常に巨大なデータを バッチ処理 するための実 行基 盤として非常に安価に利用できる上にハイパフォーマンスに動作する環境です。 例えば、筆者の業務ではGCSにおいたログファイルをBigQueryへ投入する手段としてDataflowを利用しています。テラバイトクラスのログファイルが分散処理によって数十分でDBに投入されていく様子は圧巻というほかありません。 この記事を読んだ皆様がDataflowを使って、筆者が受けた感銘を共有していただけたら非常に嬉しいです。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 社内SE(DX推進エンジニア) 執筆: @sato.taichi 、レビュー: @handa.kenta ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、長い呪文は切り捨てられる編です。 からあげさんの Stable Diffusionの内容を理解するための情報・書籍の記事 の中に出てくる 最初の75個分以降の文章は、バッサリ捨てられてしまう記事 をみて、自分でも検証してみたのが今回の記事です。 これまで、意味のある区切りとして、カンマ(,)を使っていたのですが、カンマ(,)は75個の トーク ンの一つとして重複して数えられ、カンマ(,)を削っても出力結果はほとんど変わらないことを知って愕然としました。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 tokenizer 75個を超えるトークンは切り捨てられるのか 呪文のカンマを削っても出力結果に影響はないのか まとめ 仲間募集 Stable Diffusionの過去コンテンツ tokenizer 呪文を トーク ンに分解するには、tokenizerを作成します。必要なライブラリは次のようにインストールします。今回は、Notebookの例です。 !pip install transformers ftfy regex tokenizerの作成は次のように行います。 from transformers import CLIPTokenizer tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14") 呪文を トーク ンに分解するには、次のように行います。 prompt = "anime of beautiful girl, detailed beautiful face, detailed hair, detailed perfect pupil of eyes, detailed cute mouth, detailed shoulders, detailed bust" tokens = tokenizer.tokenize(prompt) print(len(tokens), tokens[0:tokenizer.model_max_length-2]) トーク ン出力結果(改行版) 37 ['japanese</w>', 'anime</w>', 'of</w>', 'beautiful</w>', 'girl</w>', ',</w>', 'detailed</w>', 'beautiful</w>', 'face</w>', ',</w>', 'detailed</w>', 'hair</w>', ',</w>', 'detailed</w>', 'perfect</w>', 'pupil</w>', 'of</w>', 'eyes</w>', ',</w>', 'detailed</w>', 'cute</w>', 'mouth</w>', ',</w>', 'detailed</w>', 'shoulders</w>', ',</w>', 'detailed</w>', 'bust</w>'] 37の トーク ンに分解されたことがわかります。',</w>'に注目してください。これは、カンマ(,)です。カンマ(,)も トーク ンの一つにカウントされていることがわかります。 僕が実験した限り、カンマ(,)ありなしで、出力される結果に違いはありません。75個を超える トーク ンは切り捨てられることを考えると、カンマ(,)は呪文に含めないのが良いでしょう。 75個を超える トーク ンは切り捨てられるのか それでは、本当に「75個を超える トーク ンは切り捨てられるのか」実験してみましょう。 下記のようなちょうど75個の トーク ンの呪文を用意します。 prompt = "illustration of a beautiful girl, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ," tokens = tokenizer.tokenize(prompt) print(len(tokens), tokens[0:tokenizer.model_max_length-2]) image = pipe(prompt)["sample"][0] image トーク ン出力結果(改行版) 75 ['illustration</w>', 'of</w>', 'a</w>', 'beautiful</w>', 'girl</w>', ',</w>', 省略 ',</w>'] 確かに呪文は、75個の トーク ンで構成されていますね。この呪文の最後に以下の呪文を追加しましょう。75個を超える トーク ンが切り捨てられるなら、結果に影響はないはずです。 追加する呪文(改行版) deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k トーク ン出力結果(改行版) 109 ['illustration</w>', 'of</w>', 'a</w>', 'beautiful</w>', 'girl</w>', ',</w>', 省略 ',</w>'] 結果に影響はなかったですね。75個を超える トーク ンが切り捨てられることが確認できました。 呪文のカンマを削っても出力結果に影響はないのか 今度は、呪文のカンマを削っても出力結果に影響がないのかを検証してみましょう。 今回の呪文は、 美少女を高確率で出す呪文編 で使った呪文の改良版です。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed perfect pupil of eyes, detailed mouth, detailed shoulders, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed perfect pupil of eyes, detailed mouth, detailed shoulders, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 改良したのは、detailed perfect pupil of eyesとdetailed shouldersの二箇所です。 イラストなら、前回の呪文でも大丈夫なのですが、写真で試すと目や腕が変になることがあったので改良しました。 目は、detailed beautiful eyesをdetailed perfect pupil of eyesに変えました。 腕は、detailed armsをdetailed shouldersに変えました。腕は変になりやすいので、指定しないほうが無難なようです。肩を指定することで腕が出力される回数が減りました。 トーク ン出力結果(改行版) 74 ['illustration</w>','of</w>','a</w>','beautiful</w>','girl</w>', ',</w>', 'detailed</w>','beautiful</w>','face</w>', ',</w>', 'detailed</w>','hair</w>', ',</w>', 'detailed</w>','perfect</w>','pupil</w>','of</w>','eyes</w>', ',</w>', 'detailed</w>','mouth</w>', ',</w>', 'detailed</w>','shoulders</w>', ',</w>', 'detailed</w>','bust</w>', ',</w>', 'looking</w>','far</w>','away</w>', ',</w>', 'shot</w>','diag', 'on', 'ally</w>', ',</w>', 'art','station</w>', ',</w>', 'deviantart</w>', ',</w>', 'concept</w>','art</w>', ',</w>', 'digital</w>','painting</w>', ',</w>', 'award</w>','-</w>','winning</w>', ',</w>', 'cinematic</w>','post','processing</w>', ',</w>', 'cinematic</w>','scene</w>', ',</w>', 'cinematic</w>','composition</w>', ',</w>', 'cinematic</w>','lighting</w>', ',</w>', 'ove', 'rex', 'pose</w>', ',</w>', 'ray</w>','tracing</w>', ',</w>', '8</w>','k</w>'] 画像出力結果 既に トーク ンの数は74(Max 75)。これ以上、詳細な指定ができなくなるのは問題です。出力結果を見ながら呪文を改良していきましょう。 ',</w>'は削れますね。 a beautiful girlのaも削れます。girlを見れば単数であることがわかるからです。僕の試した限りはtheも削ることができます。 diagonallyが、'diag', 'on', 'ally</w>'と3つに分かれて認識されています。これは、Stable Diffusionがdiagonallyという単語を認識できていないことを示しています。 この結果を見てdiagonallyが無効だと判断するのは早計です。Stable Diffusionは、ワードでない(</w>がついていない)連続した トーク ンを有効だと認識していることもあるからです。例えば、pixivは、'pi', 'xiv</w>'と別れていますが、pixivあり/なしで、出力結果は変わってきます。つまり、pixivの呪文は有効だということです。 ワードでない(</w>がついていない)連続した トーク ンは、あり/なしで何度も試しましょう。効果があると確信できるときだけ、呪文として採用しましょう。shot diagonally(斜めに撮影する)は、何度も試した結果効果が確信できなかったので、不採用にしました。 同様にワードでない(</w>がついていない)連続した トーク ンの'ove', 'rex', 'pose</w>'も不採用にしました。 award-winningは、'award</w>', '-</w>', 'winning</w>'に分解されていたので、真ん中の '-</w>'は不要と判断し、award winningにすることにしました。 改良版の呪文(横長、コピー&ペースト用)はこちらになります。 illustration of beautiful girl detailed beautiful face detailed hair detailed perfect pupil of eyes detailed mouth detailed shoulders detailed bust looking far away artstation deviantart concept art digital painting award winning cinematic postprocessing cinematic scene cinematic composition cinematic lighting ray tracing 8k 改良版の閲覧用呪文(改行版) illustration of beautiful girl detailed beautiful face detailed hair detailed perfect pupil of eyes detailed mouth detailed shoulders detailed bust looking far away artstation deviantart concept art digital painting award winning cinematic postprocessing cinematic scene cinematic composition cinematic lighting ray tracing 8k トーク ン出力結果(改行版) 45 ['illustration</w>', 'of</w>', 'beautiful</w>', 'girl</w>', 'detailed</w>', 'beautiful</w>', 'face</w>', 'detailed</w>', 'hair</w>', 'detailed</w>', 'perfect</w>', 'pupil</w>', 'of</w>', 'eyes</w>', 'detailed</w>', 'mouth</w>', 'detailed</w>', 'shoulders</w>', 'detailed</w>', 'bust</w>', 'looking</w>', 'far</w>', 'away</w>', 'art', 'station</w>', 'deviantart</w>', 'concept</w>', 'art</w>', 'digital</w>', 'painting</w>', 'award</w>', 'winning</w>', 'cinematic</w>', 'post', 'processing</w>', 'cinematic</w>', 'scene</w>', 'cinematic</w>', 'composition</w>', 'cinematic</w>', 'lighting</w>', 'ray</w>', 'tracing</w>', '8</w>', 'k</w>'] 画像出力結果 トーク ンの個数が74から45に圧縮されました。画像のクオリティは変わっていないことが確認できると思います。 まとめ 今回は、75個を超える トーク ンは、切り捨てられることを確認しました。 さらに、呪文を圧縮するテクニックとして、カンマ(、)を削る、ワードでない(</w>がついていない)連続した トーク ンが有効かどうかをチェックすることを学びました。 次回は、 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、長い呪文は切り捨てられる編です。 からあげさんの Stable Diffusionの内容を理解するための情報・書籍の記事 の中に出てくる 最初の75個分以降の文章は、バッサリ捨てられてしまう記事 をみて、自分でも検証してみたのが今回の記事です。 これまで、意味のある区切りとして、カンマ(,)を使っていたのですが、カンマ(,)は75個の トーク ンの一つとして重複して数えられ、カンマ(,)を削っても出力結果はほとんど変わらないことを知って愕然としました。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 tokenizer 75個を超えるトークンは切り捨てられるのか 呪文のカンマを削っても出力結果に影響はないのか まとめ 仲間募集 Stable Diffusionの過去コンテンツ tokenizer 呪文を トーク ンに分解するには、tokenizerを作成します。必要なライブラリは次のようにインストールします。今回は、Notebookの例です。 !pip install transformers ftfy regex tokenizerの作成は次のように行います。 from transformers import CLIPTokenizer tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14") 呪文を トーク ンに分解するには、次のように行います。 prompt = "anime of beautiful girl, detailed beautiful face, detailed hair, detailed perfect pupil of eyes, detailed cute mouth, detailed shoulders, detailed bust" tokens = tokenizer.tokenize(prompt) print(len(tokens), tokens[0:tokenizer.model_max_length-2]) トーク ン出力結果(改行版) 37 ['japanese</w>', 'anime</w>', 'of</w>', 'beautiful</w>', 'girl</w>', ',</w>', 'detailed</w>', 'beautiful</w>', 'face</w>', ',</w>', 'detailed</w>', 'hair</w>', ',</w>', 'detailed</w>', 'perfect</w>', 'pupil</w>', 'of</w>', 'eyes</w>', ',</w>', 'detailed</w>', 'cute</w>', 'mouth</w>', ',</w>', 'detailed</w>', 'shoulders</w>', ',</w>', 'detailed</w>', 'bust</w>'] 37の トーク ンに分解されたことがわかります。',</w>'に注目してください。これは、カンマ(,)です。カンマ(,)も トーク ンの一つにカウントされていることがわかります。 僕が実験した限り、カンマ(,)ありなしで、出力される結果に違いはありません。75個を超える トーク ンは切り捨てられることを考えると、カンマ(,)は呪文に含めないのが良いでしょう。 75個を超える トーク ンは切り捨てられるのか それでは、本当に「75個を超える トーク ンは切り捨てられるのか」実験してみましょう。 下記のようなちょうど75個の トーク ンの呪文を用意します。 prompt = "illustration of a beautiful girl, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ," tokens = tokenizer.tokenize(prompt) print(len(tokens), tokens[0:tokenizer.model_max_length-2]) image = pipe(prompt)["sample"][0] image トーク ン出力結果(改行版) 75 ['illustration</w>', 'of</w>', 'a</w>', 'beautiful</w>', 'girl</w>', ',</w>', 省略 ',</w>'] 確かに呪文は、75個の トーク ンで構成されていますね。この呪文の最後に以下の呪文を追加しましょう。75個を超える トーク ンが切り捨てられるなら、結果に影響はないはずです。 追加する呪文(改行版) deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k トーク ン出力結果(改行版) 109 ['illustration</w>', 'of</w>', 'a</w>', 'beautiful</w>', 'girl</w>', ',</w>', 省略 ',</w>'] 結果に影響はなかったですね。75個を超える トーク ンが切り捨てられることが確認できました。 呪文のカンマを削っても出力結果に影響はないのか 今度は、呪文のカンマを削っても出力結果に影響がないのかを検証してみましょう。 今回の呪文は、 美少女を高確率で出す呪文編 で使った呪文の改良版です。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed perfect pupil of eyes, detailed mouth, detailed shoulders, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed perfect pupil of eyes, detailed mouth, detailed shoulders, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 改良したのは、detailed perfect pupil of eyesとdetailed shouldersの二箇所です。 イラストなら、前回の呪文でも大丈夫なのですが、写真で試すと目や腕が変になることがあったので改良しました。 目は、detailed beautiful eyesをdetailed perfect pupil of eyesに変えました。 腕は、detailed armsをdetailed shouldersに変えました。腕は変になりやすいので、指定しないほうが無難なようです。肩を指定することで腕が出力される回数が減りました。 トーク ン出力結果(改行版) 74 ['illustration</w>','of</w>','a</w>','beautiful</w>','girl</w>', ',</w>', 'detailed</w>','beautiful</w>','face</w>', ',</w>', 'detailed</w>','hair</w>', ',</w>', 'detailed</w>','perfect</w>','pupil</w>','of</w>','eyes</w>', ',</w>', 'detailed</w>','mouth</w>', ',</w>', 'detailed</w>','shoulders</w>', ',</w>', 'detailed</w>','bust</w>', ',</w>', 'looking</w>','far</w>','away</w>', ',</w>', 'shot</w>','diag', 'on', 'ally</w>', ',</w>', 'art','station</w>', ',</w>', 'deviantart</w>', ',</w>', 'concept</w>','art</w>', ',</w>', 'digital</w>','painting</w>', ',</w>', 'award</w>','-</w>','winning</w>', ',</w>', 'cinematic</w>','post','processing</w>', ',</w>', 'cinematic</w>','scene</w>', ',</w>', 'cinematic</w>','composition</w>', ',</w>', 'cinematic</w>','lighting</w>', ',</w>', 'ove', 'rex', 'pose</w>', ',</w>', 'ray</w>','tracing</w>', ',</w>', '8</w>','k</w>'] 画像出力結果 既に トーク ンの数は74(Max 75)。これ以上、詳細な指定ができなくなるのは問題です。出力結果を見ながら呪文を改良していきましょう。 ',</w>'は削れますね。 a beautiful girlのaも削れます。girlを見れば単数であることがわかるからです。僕の試した限りはtheも削ることができます。 diagonallyが、'diag', 'on', 'ally</w>'と3つに分かれて認識されています。これは、Stable Diffusionがdiagonallyという単語を認識できていないことを示しています。 この結果を見てdiagonallyが無効だと判断するのは早計です。Stable Diffusionは、ワードでない(</w>がついていない)連続した トーク ンを有効だと認識していることもあるからです。例えば、pixivは、'pi', 'xiv</w>'と別れていますが、pixivあり/なしで、出力結果は変わってきます。つまり、pixivの呪文は有効だということです。 ワードでない(</w>がついていない)連続した トーク ンは、あり/なしで何度も試しましょう。効果があると確信できるときだけ、呪文として採用しましょう。shot diagonally(斜めに撮影する)は、何度も試した結果効果が確信できなかったので、不採用にしました。 同様にワードでない(</w>がついていない)連続した トーク ンの'ove', 'rex', 'pose</w>'も不採用にしました。 award-winningは、'award</w>', '-</w>', 'winning</w>'に分解されていたので、真ん中の '-</w>'は不要と判断し、award winningにすることにしました。 改良版の呪文(横長、コピー&ペースト用)はこちらになります。 illustration of beautiful girl detailed beautiful face detailed hair detailed perfect pupil of eyes detailed mouth detailed shoulders detailed bust looking far away artstation deviantart concept art digital painting award winning cinematic postprocessing cinematic scene cinematic composition cinematic lighting ray tracing 8k 改良版の閲覧用呪文(改行版) illustration of beautiful girl detailed beautiful face detailed hair detailed perfect pupil of eyes detailed mouth detailed shoulders detailed bust looking far away artstation deviantart concept art digital painting award winning cinematic postprocessing cinematic scene cinematic composition cinematic lighting ray tracing 8k トーク ン出力結果(改行版) 45 ['illustration</w>', 'of</w>', 'beautiful</w>', 'girl</w>', 'detailed</w>', 'beautiful</w>', 'face</w>', 'detailed</w>', 'hair</w>', 'detailed</w>', 'perfect</w>', 'pupil</w>', 'of</w>', 'eyes</w>', 'detailed</w>', 'mouth</w>', 'detailed</w>', 'shoulders</w>', 'detailed</w>', 'bust</w>', 'looking</w>', 'far</w>', 'away</w>', 'art', 'station</w>', 'deviantart</w>', 'concept</w>', 'art</w>', 'digital</w>', 'painting</w>', 'award</w>', 'winning</w>', 'cinematic</w>', 'post', 'processing</w>', 'cinematic</w>', 'scene</w>', 'cinematic</w>', 'composition</w>', 'cinematic</w>', 'lighting</w>', 'ray</w>', 'tracing</w>', '8</w>', 'k</w>'] 画像出力結果 トーク ンの個数が74から45に圧縮されました。画像のクオリティは変わっていないことが確認できると思います。 まとめ 今回は、75個を超える トーク ンは、切り捨てられることを確認しました。 さらに、呪文を圧縮するテクニックとして、カンマ(、)を削る、ワードでない(</w>がついていない)連続した トーク ンが有効かどうかをチェックすることを学びました。 次回は、 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター の山下です。 今回は、TypeScriptを使って、gRPCのアプリケーションを開発する際の方法について紹介します。 gRPCとProtocol Buffers gRPCは Google の開発した様々な環境で動作する オープンソース のRPC フレームワーク です。 gRPCは負荷分散、トレース、ヘルスチェック、認証などの機能をサポートし、効率的な通信の仕組みを提供しています。 gRPCは、Protocol Buffersというインターフェース記述言語(IDL)を用いてサービスを定義して利用します。このProtocol BuffersもgRPCと同じく Google が開発しています。gRPCでアプリケーションを開発する際は、まずProtocol Buffersから通信に関するプログラムを自動的に構築して開発することになります。 Protocol Buffersは多くの言語をサポートしています。今回利用するTypeScriptを直接サポートはしていませんが、Node.jsをサポートしているので問題なく利用できます。 詳細な情報はgRPCの公式サイトを参照してください。 https://grpc.io/ Protocol Buffersについての詳細な情報は以下のURLを参照してください。 https://developers.google.com/protocol-buffers この記事では、Node.jsのサポートを利用してTypeScriptのアプリケーション開発の手順について解説します。 gRPCの通信方式 gRPCでは4種類の通信方式がある。 Unary RPC 1つのリク エス トに対して一つのレスポンスを返す一般的な通信です。 Server streaming RPC クライアントから送られてきた一つのリク エス トに対して、サーバは複数回に分けてレスポンスを返す通信方式です。 Client streaming RPC クライアントからリク エス トを分割して送る方式でサーバーはすべてのリク エス トを受け取ってからレスポンスを返す方式です。 Bidirectional streaming RPC サーバーとクライアントが一つのコネクションを確立しお互いに任意のタイミングでリク エス トとレスポンスを送りあう通信方式です。 また、gRPCでは、ブラウザで利用するgRPC WebとHTTP/2を利用して通信を行うgRPC over HTTP/2の2種類の通信方式が存在しています。 gRPC over WEBはブラウザを中心に策定された仕様となっています。このため現在は、Client streaming RPC、Bidirectional streaming RPCを行うことが出来ません。 この記事では、このうちHTTP/2を▼使ったUnary RPCの開発手順について紹介します。 TypeScriptを用いたgRPCの開発手順 TypeScriptを用いたgRPCアプリケーションは以下のような流れで開発します。 Protocol Buffersの定義を proto ファイルで行う protoc プログラムを用いて proto ファイルから ソースコード を生成する 生成したプログラムにロジックを追加して完成させる という流れになります。 ここでは、その流れを順番に追ってみます。 Protocol Buffers でサービスとメッセージを記述する Protocol Buffersではサービスとメソッド(rpc名と呼ぶ方が適切かもしれませんが、本記事ではメソッドで統一します)を定義します。メソッドが API の概念に近いものとなり、メソッドが通信でやりとりする内容をメッセージとして定義することとなります。 Protocol Buffersの例を以下に示します。なおProtocol Buffersにはバージョンがあり本記事ではバージョン3を想定しています。 syntax = "proto3"; message HelloRequest { string name = 1; } message HelloResponse { string result =1; } service Hello { rpc hello(HelloRequest) returns (HelloResponse); } 上記の定義では、 Hello というサービスと hello メソッド、 HelloRequest と HelloResponse というメッセージが定義されています。 。 hello を呼びだす場合には、 HelloRequest を引数として呼び出し、その返り値としては HelloResponse というメッセージが返ってくることを表しています。 なお、ここではProtocol Buffersの文法の詳細を述べません。詳細については、公式のドキュメントを参照してください。 https://developers.google.com/protocol-buffers/docs/proto3 記載する際は以下のスタイルガイドが参考になります。 https://developers.google.com/protocol-buffers/docs/style スタイルガイドには以下のようにサービス名、メッセージ名とフィールド名についての 命名 の規則が記載されています。 Use CamelCase (with an initial capital) for message names – for example, SongServerRequest. Use underscore_separated_names for field names (including oneof field and extension names) – for example, song_name. このガイドの内容に従わなくても問題はおきません。しかし、従っていない場合は生成される ソースコード が不自然なものとなってしまいます。 例えば、フィールド名を userId のような名前を付けた場合、これに対応するメソッドやプロパティの名前は getUserid 、 setUserid といった形になってしまいます。 一方で user_id というフィールド名を用いた場合は getUserId 、 setUserId という名前で生成されます。コードの読みやすさなどの観点からフィールド名にはスネークケースを用いる方が良さそうですね。 Protocol Buffersの更新について Protocol Buffersのprotoファイルを更新して、メッセージのフォーマットを変更する場合には注意が必要となります。 特に、フィールド番号は安易に変更、削除してしまうと古いプログラムと新しいプログラムでメッセージのフォーマットが一致しなくなり通信できなくなってしまうので注意が必要です。 極力新しいフィールドを追加していく形で更新していく事が望ましいです。 また削除も可能であれば避け OBSOLETE_ といった プレフィックス をつけて残しておく事が望ましいです。 後々誤って削除したフィールド番号が再利用されてしまうといったトラブルを回避するためです。 また各種メッセージの種類には互換性があり、同じフィールド番号でもメッセージの種類の変更は可能な場合があります。 その他の注意点については公式のドキュメントを熟読し、慎重に更新を行っていく必要があるので注意してください。 https://developers.google.com/protocol-buffers/docs/proto3#updating Protocol Buffersから ソースコード を生成する protocプログラムとそのオプションについて Protocol Buffersからコードを生成するプログラム( protoc )は、オプションの記述方法に注意が必要です。 protoc を利用する際は、 xxx_out=.... というオプションが並ぶことになります。 このオプションは、以下のように解釈します。 --xxx_out は プラグイン と出力先の指定を意味します。これは、 proto-gen-xxx という プラグイン 名の場合は、 xxx_out という対応関係になっています。 proto-gen-go プラグイン なら --go_out 。 proto-gen-grpc-gateway プラグイン なら --grpc-gateway_out という具合になっています。 プラグイン 自体もオプションも同時に指定することが出来て、 --xxx_out=プラグインのオプション:出力先 という形になります。 例えば、 --js_out=import_style=commonjs,binary:${PROTO_DEST} と書いてある場合を考えます。 これは、 js_out プラグイン に import_style=commonjs,binary(=true) という引数を渡すことになります。そして、その出力先は ${PROTO_DEST} ということです。 TypeScript用のprotocについて protoc は Node.js に対応していますが、TypeScriptの型定義などを直接生成する機能は持っていません。 今回は、 grpc_tools_node_protoc_ts を用いて protoc の生成した Node.js の ソースコード に型定義を自動生成して利用します。これは、 grpc-tools というgRPC公式に含まれている grpc_tools_node_protoc というツールを拡張したものです。 以下が公式ドキュメントとその使い方です。 https://github.com/agreatfool/grpc_tools_node_protoc_ts#how-to-use # ソースコードの出力先 PROTO_DEST=./src/proto # protoファイルが置いてあるディレクトリ PROTO_DIR=./proto # Protocol BuffersからnodeのgRPCコードを自動生成 grpc_tools_node_protoc \ --js_out=import_style=commonjs,binary:${PROTO_DEST} \ --grpc_out=${PROTO_DEST} \ --plugin=protoc-gen-grpc=$(which grpc_tools_node_protoc_plugin) \ -I ${PROTO_SRC} \ ${PROTO_SRC}/* # typescript用の型定義を作成 grpc_tools_node_protoc \ --plugin=protoc-gen-ts=$(yarn bin)/protoc-gen-ts \ --ts_out=${PROTO_DEST} \ -I ${PROTO_SRC} \ ${PROTO_SRC}/* もしくは以下のように一括で生成する方法もあります。 # 定義と実装を同時に生成 yarn run grpc_tools_node_protoc \ --plugin=protoc-gen-ts=$(yarn bin)/protoc-gen-ts \ --ts_out=grpc_js:${PROTO_DEST} \ --js_out=import_style=commonjs,binary:${PROTO_DEST} \ --grpc_out=grpc_js:${PROTO_DEST} \ -I ${PROTO_DIR} \ ${PROTO_DIR}/*.proto 生成されたプログラムを利用してみる Hello サービスの簡単なサーバ、クライアントの実装を以下に示します。 通信に関わる処理は全てgRPC側が行ってくれているため、実際に記述する部分はロジックに対応する部分だけとなります。通信に用いるメッセージを組み立てる関数も自動生成されているので、それを利用して構築できます。 // サーバプログラム import * as grpc from '@grpc/grpc-js' ; import { sendUnaryData } from '@grpc/grpc-js/build/src/server-call' ; import { HelloRequest , HelloResponse } from '../proto/hello_pb' ; import { HelloService } from '../proto/hello_grpc_pb' ; const HelloServer = { hello: ( call: grpc.ServerUnaryCall < HelloRequest , HelloResponse >, callback: sendUnaryData < HelloResponse >) : void => { const request = call.request ; const response = new HelloResponse (); console .log ( "Message from client" ); response.setResult ( "Hello," + request.getName ()) callback ( null , response ); } } function serve () : void { const server = new grpc.Server (); server.addService ( HelloService , HelloServer ); server.bindAsync ( `localhost:6543` , grpc.ServerCredentials.createInsecure (), ( err , port ) => { if ( err ) { throw err ; } console .log ( `Listening on ${ port } ` ); server.start (); } ); } serve (); // クライアントプログラム import * as grpc from '@grpc/grpc-js' ; import { HelloClient } from '../proto/hello_grpc_pb' ; import { HelloRequest , HelloResponse } from '../proto/hello_pb' ; function hello () : Promise < HelloResponse > { const client = new HelloClient ( `localhost:6543` , grpc.credentials.createInsecure (), ); // HelloRequestを作るためのクラス、メソッドが用意されているのでそれを用いてメッセージを作成する const request = new HelloRequest (); request.setName ( "ISID" ); // サーバに対してサービスの実行を要求する return new Promise < HelloResponse >(( resolve , reject ) => { console .log ( "Send Hello Message" ); client.hello ( request , ( err , response ) => { if ( err ) { return reject ( err ); } // ここで結果を受け取っている console .log ( "Receive Message" ); return resolve ( response ); } ); } ); } (async () => { console .log ( "Client Start" ); const result = await hello (); console .log ( result.getResult ()); } )(); 実際のプロジェクト構成と動作例 ここでは、今回のサンプルで利用したプロジェクトの構成を紹介します。 プロジェクト構成例 ディレクト リの構成は以下のような構成です。 . ├── package.json ├── proto │   └── hello.proto ├── scripts │   └── build-protos.sh ├── src │   ├── client │   │   └── index.ts │   ├── proto │   └── server │   └── index.ts └── tsconfig.json また、package. json の中身は以下のような内容です。 { " name ": " grpc-hello ", " version ": " 1.0.0 ", " main ": " index.js ", " license ": " MIT ", " dependencies ": { } , " scripts ": { " lint ": " yarn run eslint --fix --ext .ts src ", " clean ": " rm -rf ./dist && rm -rf ./src/proto && mkdir -p ./src/proto ", " build ": " sh ./scripts/build-protos.sh ./hello.proto ./src/proto && yarn run tsc; cp -r ./src/proto ./dist/src/proto " , } , " devDependencies ": { " @grpc/grpc-js ": " ^1.4.2 ", " @types/eslint ": " ^7.28.2 ", " @types/google-protobuf ": " ^3.15.5 ", " @types/node ": " ^16.11.7 ", " @typescript-eslint/eslint-plugin ": " ^5.3.0 ", " @typescript-eslint/parser ": " ^5.3.0 ", " eslint ": " ^8.1.0 ", " grpc-tools ": " ^1.11.2 ", " grpc_tools_node_protoc_ts ": " ^5.3.2 ", " ts-node ": " ^10.4.0 ", " tsconfig-paths ": " ^3.11.0 ", " typescript ": " ^4.4.4 " } } 動作確認 まず yarn build で Protocol Buffers からコード生成、TypeScriptから JavaScript へのトランスパイルを実行します。 $ yarn $ yarn build サーバの起動 $ node ./dist/src/server/ Listening on 6543 クライアントの実行 $ node ./dist/src/client Client Start Send Hello Message Receive Message Hello,ISID サーバー側のログも確認すると Message from client というようなログが出ています。 gRPCを使った通信プログラムが実装できてそうです。 まとめ 今回は、gRPCを用いたアプリケーション開発の方法やその注意点について紹介しました。 gRPCは Protocol Buffers を定義するだけで高品質な通信プログラムが実装できる素晴しい技術ですね。 機会があれば積極的に利用していきたいと思います。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募お待ちしています。 ソリューションアーキテクト 執筆: @yamashita.tsuyoshi 、レビュー: @handa.kenta ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター の山下です。 今回は、TypeScriptを使って、gRPCのアプリケーションを開発する際の方法について紹介します。 gRPCとProtocol Buffers gRPCは Google の開発した様々な環境で動作する オープンソース のRPC フレームワーク です。 gRPCは負荷分散、トレース、ヘルスチェック、認証などの機能をサポートし、効率的な通信の仕組みを提供しています。 gRPCは、Protocol Buffersというインターフェース記述言語(IDL)を用いてサービスを定義して利用します。このProtocol BuffersもgRPCと同じく Google が開発しています。gRPCでアプリケーションを開発する際は、まずProtocol Buffersから通信に関するプログラムを自動的に構築して開発することになります。 Protocol Buffersは多くの言語をサポートしています。今回利用するTypeScriptを直接サポートはしていませんが、Node.jsをサポートしているので問題なく利用できます。 詳細な情報はgRPCの公式サイトを参照してください。 https://grpc.io/ Protocol Buffersについての詳細な情報は以下のURLを参照してください。 https://developers.google.com/protocol-buffers この記事では、Node.jsのサポートを利用してTypeScriptのアプリケーション開発の手順について解説します。 gRPCの通信方式 gRPCでは4種類の通信方式がある。 Unary RPC 1つのリク エス トに対して一つのレスポンスを返す一般的な通信です。 Server streaming RPC クライアントから送られてきた一つのリク エス トに対して、サーバは複数回に分けてレスポンスを返す通信方式です。 Client streaming RPC クライアントからリク エス トを分割して送る方式でサーバーはすべてのリク エス トを受け取ってからレスポンスを返す方式です。 Bidirectional streaming RPC サーバーとクライアントが一つのコネクションを確立しお互いに任意のタイミングでリク エス トとレスポンスを送りあう通信方式です。 また、gRPCでは、ブラウザで利用するgRPC WebとHTTP/2を利用して通信を行うgRPC over HTTP/2の2種類の通信方式が存在しています。 gRPC over WEBはブラウザを中心に策定された仕様となっています。このため現在は、Client streaming RPC、Bidirectional streaming RPCを行うことが出来ません。 この記事では、このうちHTTP/2を▼使ったUnary RPCの開発手順について紹介します。 TypeScriptを用いたgRPCの開発手順 TypeScriptを用いたgRPCアプリケーションは以下のような流れで開発します。 Protocol Buffersの定義を proto ファイルで行う protoc プログラムを用いて proto ファイルから ソースコード を生成する 生成したプログラムにロジックを追加して完成させる という流れになります。 ここでは、その流れを順番に追ってみます。 Protocol Buffers でサービスとメッセージを記述する Protocol Buffersではサービスとメソッド(rpc名と呼ぶ方が適切かもしれませんが、本記事ではメソッドで統一します)を定義します。メソッドが API の概念に近いものとなり、メソッドが通信でやりとりする内容をメッセージとして定義することとなります。 Protocol Buffersの例を以下に示します。なおProtocol Buffersにはバージョンがあり本記事ではバージョン3を想定しています。 syntax = "proto3"; message HelloRequest { string name = 1; } message HelloResponse { string result =1; } service Hello { rpc hello(HelloRequest) returns (HelloResponse); } 上記の定義では、 Hello というサービスと hello メソッド、 HelloRequest と HelloResponse というメッセージが定義されています。 。 hello を呼びだす場合には、 HelloRequest を引数として呼び出し、その返り値としては HelloResponse というメッセージが返ってくることを表しています。 なお、ここではProtocol Buffersの文法の詳細を述べません。詳細については、公式のドキュメントを参照してください。 https://developers.google.com/protocol-buffers/docs/proto3 記載する際は以下のスタイルガイドが参考になります。 https://developers.google.com/protocol-buffers/docs/style スタイルガイドには以下のようにサービス名、メッセージ名とフィールド名についての 命名 の規則が記載されています。 Use CamelCase (with an initial capital) for message names – for example, SongServerRequest. Use underscore_separated_names for field names (including oneof field and extension names) – for example, song_name. このガイドの内容に従わなくても問題はおきません。しかし、従っていない場合は生成される ソースコード が不自然なものとなってしまいます。 例えば、フィールド名を userId のような名前を付けた場合、これに対応するメソッドやプロパティの名前は getUserid 、 setUserid といった形になってしまいます。 一方で user_id というフィールド名を用いた場合は getUserId 、 setUserId という名前で生成されます。コードの読みやすさなどの観点からフィールド名にはスネークケースを用いる方が良さそうですね。 Protocol Buffersの更新について Protocol Buffersのprotoファイルを更新して、メッセージのフォーマットを変更する場合には注意が必要となります。 特に、フィールド番号は安易に変更、削除してしまうと古いプログラムと新しいプログラムでメッセージのフォーマットが一致しなくなり通信できなくなってしまうので注意が必要です。 極力新しいフィールドを追加していく形で更新していく事が望ましいです。 また削除も可能であれば避け OBSOLETE_ といった プレフィックス をつけて残しておく事が望ましいです。 後々誤って削除したフィールド番号が再利用されてしまうといったトラブルを回避するためです。 また各種メッセージの種類には互換性があり、同じフィールド番号でもメッセージの種類の変更は可能な場合があります。 その他の注意点については公式のドキュメントを熟読し、慎重に更新を行っていく必要があるので注意してください。 https://developers.google.com/protocol-buffers/docs/proto3#updating Protocol Buffersから ソースコード を生成する protocプログラムとそのオプションについて Protocol Buffersからコードを生成するプログラム( protoc )は、オプションの記述方法に注意が必要です。 protoc を利用する際は、 xxx_out=.... というオプションが並ぶことになります。 このオプションは、以下のように解釈します。 --xxx_out は プラグイン と出力先の指定を意味します。これは、 proto-gen-xxx という プラグイン 名の場合は、 xxx_out という対応関係になっています。 proto-gen-go プラグイン なら --go_out 。 proto-gen-grpc-gateway プラグイン なら --grpc-gateway_out という具合になっています。 プラグイン 自体もオプションも同時に指定することが出来て、 --xxx_out=プラグインのオプション:出力先 という形になります。 例えば、 --js_out=import_style=commonjs,binary:${PROTO_DEST} と書いてある場合を考えます。 これは、 js_out プラグイン に import_style=commonjs,binary(=true) という引数を渡すことになります。そして、その出力先は ${PROTO_DEST} ということです。 TypeScript用のprotocについて protoc は Node.js に対応していますが、TypeScriptの型定義などを直接生成する機能は持っていません。 今回は、 grpc_tools_node_protoc_ts を用いて protoc の生成した Node.js の ソースコード に型定義を自動生成して利用します。これは、 grpc-tools というgRPC公式に含まれている grpc_tools_node_protoc というツールを拡張したものです。 以下が公式ドキュメントとその使い方です。 https://github.com/agreatfool/grpc_tools_node_protoc_ts#how-to-use # ソースコードの出力先 PROTO_DEST=./src/proto # protoファイルが置いてあるディレクトリ PROTO_DIR=./proto # Protocol BuffersからnodeのgRPCコードを自動生成 grpc_tools_node_protoc \ --js_out=import_style=commonjs,binary:${PROTO_DEST} \ --grpc_out=${PROTO_DEST} \ --plugin=protoc-gen-grpc=$(which grpc_tools_node_protoc_plugin) \ -I ${PROTO_SRC} \ ${PROTO_SRC}/* # typescript用の型定義を作成 grpc_tools_node_protoc \ --plugin=protoc-gen-ts=$(yarn bin)/protoc-gen-ts \ --ts_out=${PROTO_DEST} \ -I ${PROTO_SRC} \ ${PROTO_SRC}/* もしくは以下のように一括で生成する方法もあります。 # 定義と実装を同時に生成 yarn run grpc_tools_node_protoc \ --plugin=protoc-gen-ts=$(yarn bin)/protoc-gen-ts \ --ts_out=grpc_js:${PROTO_DEST} \ --js_out=import_style=commonjs,binary:${PROTO_DEST} \ --grpc_out=grpc_js:${PROTO_DEST} \ -I ${PROTO_DIR} \ ${PROTO_DIR}/*.proto 生成されたプログラムを利用してみる Hello サービスの簡単なサーバ、クライアントの実装を以下に示します。 通信に関わる処理は全てgRPC側が行ってくれているため、実際に記述する部分はロジックに対応する部分だけとなります。通信に用いるメッセージを組み立てる関数も自動生成されているので、それを利用して構築できます。 // サーバプログラム import * as grpc from '@grpc/grpc-js' ; import { sendUnaryData } from '@grpc/grpc-js/build/src/server-call' ; import { HelloRequest , HelloResponse } from '../proto/hello_pb' ; import { HelloService } from '../proto/hello_grpc_pb' ; const HelloServer = { hello: ( call: grpc.ServerUnaryCall < HelloRequest , HelloResponse >, callback: sendUnaryData < HelloResponse >) : void => { const request = call.request ; const response = new HelloResponse (); console .log ( "Message from client" ); response.setResult ( "Hello," + request.getName ()) callback ( null , response ); } } function serve () : void { const server = new grpc.Server (); server.addService ( HelloService , HelloServer ); server.bindAsync ( `localhost:6543` , grpc.ServerCredentials.createInsecure (), ( err , port ) => { if ( err ) { throw err ; } console .log ( `Listening on ${ port } ` ); server.start (); } ); } serve (); // クライアントプログラム import * as grpc from '@grpc/grpc-js' ; import { HelloClient } from '../proto/hello_grpc_pb' ; import { HelloRequest , HelloResponse } from '../proto/hello_pb' ; function hello () : Promise < HelloResponse > { const client = new HelloClient ( `localhost:6543` , grpc.credentials.createInsecure (), ); // HelloRequestを作るためのクラス、メソッドが用意されているのでそれを用いてメッセージを作成する const request = new HelloRequest (); request.setName ( "ISID" ); // サーバに対してサービスの実行を要求する return new Promise < HelloResponse >(( resolve , reject ) => { console .log ( "Send Hello Message" ); client.hello ( request , ( err , response ) => { if ( err ) { return reject ( err ); } // ここで結果を受け取っている console .log ( "Receive Message" ); return resolve ( response ); } ); } ); } (async () => { console .log ( "Client Start" ); const result = await hello (); console .log ( result.getResult ()); } )(); 実際のプロジェクト構成と動作例 ここでは、今回のサンプルで利用したプロジェクトの構成を紹介します。 プロジェクト構成例 ディレクト リの構成は以下のような構成です。 . ├── package.json ├── proto │   └── hello.proto ├── scripts │   └── build-protos.sh ├── src │   ├── client │   │   └── index.ts │   ├── proto │   └── server │   └── index.ts └── tsconfig.json また、package. json の中身は以下のような内容です。 { " name ": " grpc-hello ", " version ": " 1.0.0 ", " main ": " index.js ", " license ": " MIT ", " dependencies ": { } , " scripts ": { " lint ": " yarn run eslint --fix --ext .ts src ", " clean ": " rm -rf ./dist && rm -rf ./src/proto && mkdir -p ./src/proto ", " build ": " sh ./scripts/build-protos.sh ./hello.proto ./src/proto && yarn run tsc; cp -r ./src/proto ./dist/src/proto " , } , " devDependencies ": { " @grpc/grpc-js ": " ^1.4.2 ", " @types/eslint ": " ^7.28.2 ", " @types/google-protobuf ": " ^3.15.5 ", " @types/node ": " ^16.11.7 ", " @typescript-eslint/eslint-plugin ": " ^5.3.0 ", " @typescript-eslint/parser ": " ^5.3.0 ", " eslint ": " ^8.1.0 ", " grpc-tools ": " ^1.11.2 ", " grpc_tools_node_protoc_ts ": " ^5.3.2 ", " ts-node ": " ^10.4.0 ", " tsconfig-paths ": " ^3.11.0 ", " typescript ": " ^4.4.4 " } } 動作確認 まず yarn build で Protocol Buffers からコード生成、TypeScriptから JavaScript へのトランスパイルを実行します。 $ yarn $ yarn build サーバの起動 $ node ./dist/src/server/ Listening on 6543 クライアントの実行 $ node ./dist/src/client Client Start Send Hello Message Receive Message Hello,ISID サーバー側のログも確認すると Message from client というようなログが出ています。 gRPCを使った通信プログラムが実装できてそうです。 まとめ 今回は、gRPCを用いたアプリケーション開発の方法やその注意点について紹介しました。 gRPCは Protocol Buffers を定義するだけで高品質な通信プログラムが実装できる素晴しい技術ですね。 機会があれば積極的に利用していきたいと思います。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募お待ちしています。 ソリューションアーキテクト 執筆: @yamashita.tsuyoshi 、レビュー: @handa.kenta ( Shodo で執筆されました )
アバター
はじめに ISID X(クロス) イノベーション 本部 の三浦です。 筆者の関わってる案件では、コンテナ利用、 AWS Fargate利用を進めております。 AWS Fargateのお手軽さは非常に重宝しております。 しかし、そこで問題になってくるのが、管理接続、踏み台系をどうするかです。 アプリケーション本体をせっかく AWS Fargateでやっているので、管理系接続、踏み台的な作業もできるだけ非EC2でやりたいですよね? ということで、 AWS FargateでECS Exec、session managerをどのように運用に使っていけるか紹介いたします。 目次 はじめに 目次 想定作業、目標 基本のECS Exec実行 aws ssm start-session start-session with AWS-StartPortForwardingSession start-session with AWS-StartPortForwardingSessionToRemoteHost 番外:ECS FargateでSSMセッションマネージャーのリモートホストのポートフォワード環境を構築する ECS Exec with 運用スクリプト まとめ 想定作業、目標 下記のような想定作業、目標となります。 想定作業: RDSに接続し管理作業(pgdump、pgrestore、レコードの状態確認) ECS Fagateが使ってるEFSのファイル配置、ファイル取得 トラブル時のECSの状態把握(設定ファイル、 環境変数 等) 目標: 管理用のEC2を建てたくない 筆者が関係しているアカウントは200アカウント以上あり、各アカウントに踏み台を立てるのも、集中管理踏み台で VPC ピアリングを考えるのも非常にどちらも避けたい感覚です(というか今苦しんでます) 権限管理を AWS のロールに寄せたい ec2環境では作業時にwinパスワード、 ssh キーを払い出すような仕組みを実装しているのですが(チケット管理+ssm)、トラブルが一定頻度で発生しています。また、利用者としても踏み台への接続情報(接続経路、IP)、認証情報を意識するのは煩雑です。 監査ログを AWS に寄せたい ECS Execでメンテナンスコマンドの手打ちを辞めたい ローカルから、ポート フォワ ード等で デバッグ 用のセッションを張りたい 基本のECS Exec実行 基本のECS Exec実行です。 工夫としてはタスクIDの取得が煩雑なため、環境情報の取得を自動取得にしているだけです。本取得条件は、1 クラスタ ーに1ecsサービスとなっているので、ECS クラスタ ー、サービスの状況に応じ、適宜クエリ条件は編集してください。 cl = $( aws ecs list-clusters | jq -r ' .clusterArns[0] ' ) prefix = ` echo ${cl} | sed -E ' s/.+cluster\///g ' ` taskarn = $( aws ecs list-tasks --cluster ${cl} | jq -r ' .taskArns[0] ' ) taskid = ` echo ${taskarn} | sed -E ' s/.+task\/.+\///g ' ` CONTAINER_NAME = " ${prefix} -manager-container " echo ${cl} ; \ echo ${prefix} ; \ echo ${taskarn} ; \ echo ${taskid} ; \ echo ${CONTAINER_NAME} ; \ aws ecs execute-command \ --region ap-northeast-1 \ --cluster ${cl} \ --task ${taskarn} \ --container ${CONTAINER_NAME} \ --command " /bin/sh " \ --interactive あと、ECS Execは、cloud shellから実行すれば、アクセスキー、シークレットキーいらずで、 AWS consoleアクセス、フェデレーション管理に寄せることができます。 aws ssm start-session 参考記事: https://winebarrel.hatenablog.com/entry/2021/10/23/165720 次に、対話式シェル以外でもいろいろできないか探っていきます。 上記ブログで下のようなコメントがあり、私は下のところで止まっておりました。 ECS ExecがどうもマネージドなSSM Agentを使って動いているということはわかっていたが、実際どうなっているのかよくわからなかった。 ・・・・ aws ssm start-sessionを実行できそうな雰囲気があるが、--targetに何を渡せばいいのかよくわからなかった。 が、続けて読んでいくと、 ソースコード を読めばtargetの書式が書かれてるとのこと。 https://github.com/aws/aws-cli/blob/c0edee0a7427b6e7b654df0696015e96105497a3/awscli/customizations/ecs/executecommand.py#L61-L73 def build_ssm_request_paramaters (response, client): cluster_name = response[ 'clusterArn' ].split( '/' )[- 1 ] task_id = response[ 'taskArn' ].split( '/' )[- 1 ] container_name = response[ 'containerName' ] # in order to get container run-time id # we need to make a call to describe-tasks container_runtime_id = \ get_container_runtime_id(client, container_name, task_id, cluster_name) target = "ecs:{}_{}_{}" .format(cluster_name, task_id, container_runtime_id) ssm_request_params = { "Target" : target} return ssm_request_params ソースコード を読めば確かに早かったですね。。。 ということで、 aws ssm start-sessionの各ドキュメントを試します。 まずは基本のsession接続。 cl = $( aws ecs list-clusters | jq -r ' .clusterArns[0] ' ) prefix = ` echo ${cl} | sed -E ' s/.+cluster\///g ' ` taskarn = $( aws ecs list-tasks --cluster ${cl} | jq -r ' .taskArns[] ' ) taskid = ` echo ${taskarn} | sed -E ' s/.+task\/.+\///g ' ` CONTAINER_NAME = " ${prefix} -manager-container " CONTAINER_ID = $( aws ecs describe-tasks --cluster $cl --task $taskid | jq -r --arg CONTAINER_NAME $CONTAINER_NAME ' .tasks[0].containers[] | select(.name == $CONTAINER_NAME).runtimeId ' ) echo ${cl} ; \ echo ${prefix} ; \ echo ${taskarn} ; \ echo ${taskid} ; \ echo ${CONTAINER_NAME} ; echo ${CONTAINER_ID} ; aws ssm start-session --target ecs: ${prefix} _ ${taskid} _ ${CONTAINER_ID} パラメータとしてCONTAINER_IDの取得が増えておりますが、つながりました。まあ、これだけだとecs execと同じためなんのありがたさもありませんが。 なお、 AWS Fargateでのstart-session利用は AWS CLI の ソースコード を読んで得た知見であり、 AWS がサポートしている使い方ではありません。 start-session with AWS -StartPortForwardingSession では、次に、 AWS -StartPortForwardingSessionを試していきましょう。 もしできれば、接続トラブル時の切り分け作業、インターネットに公開するのに抵抗のある管理ポートへのアクセス等、いろいろ使い道があります。 #前述のおまじない aws ssm start-session --target ecs: ${prefix} _ ${taskid} _ ${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSession --parameters ' {"portNumber":["80"],"localPortNumber":["18080"]} ' ドキュメントとパラメータを追加し実行です。 ということで、つながりました。まあ、cloudshellからだと使い道がありませんが(バックグランド実行のしかたがわかりませんでした)、ローカルマシンから利用するには便利そうです。 start-session with AWS -StartPortForwardingSessionToRemoteHost では、次に、 AWS -StartPortForwardingSessionToRemoteHostを試します。 「 AWS -StartPortForwardingSessionToRemoteHost」って何?って人は、 クラスメソッド様のAWS System Managerセッションマネージャーがリモートホストのポートフォワードに対応しました をご覧ください。 ざっくりいってしまうと、session managerの対象ホストから他のホストにポート フォワ ードできる優れものです。session managerに対応していないRDSへポート フォワ ードできたりします。 これができれば、ローカルのGUIDB管理ツールからRDSへ接続が可能となります( CLI だと厳しいというメンバが一定数おりそれ用の対応検討です)。 #前述のおまじない aws ssm start-session \ --target ecs: ${prefix} _ ${taskid} _ ${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters ' {"host":["RDSエンドポイント],"portNumber":["3306"], "localPortNumber":["3306"]} ' で、実施結果ですが、、。 2022/07、2022/09で二回ほど試しておりますが、現行の AWS Fargateに入ってるエージェントバージョンが未対応とのこと。当面、ローカルからの直接RDS接続はお預けです。 番外:ECS FargateでSSMセッションマネージャーの リモートホスト のポート フォワ ード環境を構築する ECS FargateでSSMセッションマネージャーのリモートホストのポートフォワード環境を構築する にかかれているように、Fargate基盤のエージェントを利用するのではなく、ssmエージェント設定したコンテナをfargateにデプロイすれば リモートホスト へのポート フォワ ード環境の構築は可能です。 また、上記の方法以外にも、下記のような仕込みをすることで対象コンテナへのポート フォワ ードRDS接続はできそうです。 これでコンテナに[stone](https://www.gcd.org/sengoku/stone/Welcome.ja.html)でも入れておけば、Fargateのタスクを踏み台にしてデータベースなどへのアクセスができる。 参考記事: https://winebarrel.hatenablog.com/entry/2021/10/23/165720 ECS Exec with 運用 スクリプト 前述までの内容で、ポート フォワ ード、対話式でいろいろな管理オペレーションができそうということは見えてきました。 が、やはり、定型作業は単 純化 していきたいので対話式以外でのメンテナンス方式を考えていきます。 [アップデート] 実行中のコンテナに乗り込んでコマンドを実行できる「ECS Exec」が公開されました で、上の記事を見てると下記のような気になる記述が。 aws の公式ドキュメントをみてると、 /bin/sh を呼ぶ例しか書いていないのですが、任意のコマンドで呼べるんですね。 ということで、運用 スクリプト をコンテナ内に配置し呼び出してみます。 #前述のおまじない #pgdump⇒s3アップロードをしている運用スクリプトを呼び出している例 aws ecs execute-command \ --region ap-northeast-1 \ --cluster ${cl} \ --task ${taskarn} \ --container ${CONTAINER_NAME} \ --command " /bin/sh -c '/work/backup.sh backupComment' " \ --interactive #s3ダウンロード⇒pgrestoreをしている運用スクリプトを呼び出している例 aws ecs execute-command \ --region ap-northeast-1 \ --cluster ${cl} \ --task ${taskarn} \ --container ${CONTAINER_NAME} \ --command " /bin/sh -c '/work/restore.sh my-dev_20220902-153423_backupComment.dump' " \ --interactive こんな感じで、運用 スクリプト をECS Execから呼びだすことができます(なお、重い運用JOBの場合は、専用のタスクを起動した方がよいと考えております)。 ということで、既存構成に多少の手を加えることにより、ECS Execからメンテナンスをする仕組みが実装できました。 ECS Execで呼び出せるように運用 スクリプト を定義しておけば、今後下記のようなこともできそうです。 今までどおりcloudshellから Ops が手動でECS Execにて運用 スクリプト を起動する ChatOpsでECS Exec経由で運用 スクリプト を起動する チケット管理ツールのワークフローからECS Exec経由で運用 スクリプト を起動する(一部のssm run-commandはこの方式で実施しています) まとめ ということで、 AWS Fargate利用時の運用タスクの実行方法についてご紹介してみました。 執筆: @miura.toshihiko ( Shodo で執筆されました )
アバター
はじめに ISID X(クロス) イノベーション 本部 の三浦です。 筆者の関わってる案件では、コンテナ利用、 AWS Fargate利用を進めております。 AWS Fargateのお手軽さは非常に重宝しております。 しかし、そこで問題になってくるのが、管理接続、踏み台系をどうするかです。 アプリケーション本体をせっかく AWS Fargateでやっているので、管理系接続、踏み台的な作業もできるだけ非EC2でやりたいですよね? ということで、 AWS FargateでECS Exec、session managerをどのように運用に使っていけるか紹介いたします。 目次 はじめに 目次 想定作業、目標 基本のECS Exec実行 aws ssm start-session start-session with AWS-StartPortForwardingSession start-session with AWS-StartPortForwardingSessionToRemoteHost 番外:ECS FargateでSSMセッションマネージャーのリモートホストのポートフォワード環境を構築する ECS Exec with 運用スクリプト まとめ 想定作業、目標 下記のような想定作業、目標となります。 想定作業: RDSに接続し管理作業(pgdump、pgrestore、レコードの状態確認) ECS Fagateが使ってるEFSのファイル配置、ファイル取得 トラブル時のECSの状態把握(設定ファイル、 環境変数 等) 目標: 管理用のEC2を建てたくない 筆者が関係しているアカウントは200アカウント以上あり、各アカウントに踏み台を立てるのも、集中管理踏み台で VPC ピアリングを考えるのも非常にどちらも避けたい感覚です(というか今苦しんでます) 権限管理を AWS のロールに寄せたい ec2環境では作業時にwinパスワード、 ssh キーを払い出すような仕組みを実装しているのですが(チケット管理+ssm)、トラブルが一定頻度で発生しています。また、利用者としても踏み台への接続情報(接続経路、IP)、認証情報を意識するのは煩雑です。 監査ログを AWS に寄せたい ECS Execでメンテナンスコマンドの手打ちを辞めたい ローカルから、ポート フォワ ード等で デバッグ 用のセッションを張りたい 基本のECS Exec実行 基本のECS Exec実行です。 工夫としてはタスクIDの取得が煩雑なため、環境情報の取得を自動取得にしているだけです。本取得条件は、1 クラスタ ーに1ecsサービスとなっているので、ECS クラスタ ー、サービスの状況に応じ、適宜クエリ条件は編集してください。 cl = $( aws ecs list-clusters | jq -r ' .clusterArns[0] ' ) prefix = ` echo ${cl} | sed -E ' s/.+cluster\///g ' ` taskarn = $( aws ecs list-tasks --cluster ${cl} | jq -r ' .taskArns[0] ' ) taskid = ` echo ${taskarn} | sed -E ' s/.+task\/.+\///g ' ` CONTAINER_NAME = " ${prefix} -manager-container " echo ${cl} ; \ echo ${prefix} ; \ echo ${taskarn} ; \ echo ${taskid} ; \ echo ${CONTAINER_NAME} ; \ aws ecs execute-command \ --region ap-northeast-1 \ --cluster ${cl} \ --task ${taskarn} \ --container ${CONTAINER_NAME} \ --command " /bin/sh " \ --interactive あと、ECS Execは、cloud shellから実行すれば、アクセスキー、シークレットキーいらずで、 AWS consoleアクセス、フェデレーション管理に寄せることができます。 aws ssm start-session 参考記事: https://winebarrel.hatenablog.com/entry/2021/10/23/165720 次に、対話式シェル以外でもいろいろできないか探っていきます。 上記ブログで下のようなコメントがあり、私は下のところで止まっておりました。 ECS ExecがどうもマネージドなSSM Agentを使って動いているということはわかっていたが、実際どうなっているのかよくわからなかった。 ・・・・ aws ssm start-sessionを実行できそうな雰囲気があるが、--targetに何を渡せばいいのかよくわからなかった。 が、続けて読んでいくと、 ソースコード を読めばtargetの書式が書かれてるとのこと。 https://github.com/aws/aws-cli/blob/c0edee0a7427b6e7b654df0696015e96105497a3/awscli/customizations/ecs/executecommand.py#L61-L73 def build_ssm_request_paramaters (response, client): cluster_name = response[ 'clusterArn' ].split( '/' )[- 1 ] task_id = response[ 'taskArn' ].split( '/' )[- 1 ] container_name = response[ 'containerName' ] # in order to get container run-time id # we need to make a call to describe-tasks container_runtime_id = \ get_container_runtime_id(client, container_name, task_id, cluster_name) target = "ecs:{}_{}_{}" .format(cluster_name, task_id, container_runtime_id) ssm_request_params = { "Target" : target} return ssm_request_params ソースコード を読めば確かに早かったですね。。。 ということで、 aws ssm start-sessionの各ドキュメントを試します。 まずは基本のsession接続。 cl = $( aws ecs list-clusters | jq -r ' .clusterArns[0] ' ) prefix = ` echo ${cl} | sed -E ' s/.+cluster\///g ' ` taskarn = $( aws ecs list-tasks --cluster ${cl} | jq -r ' .taskArns[] ' ) taskid = ` echo ${taskarn} | sed -E ' s/.+task\/.+\///g ' ` CONTAINER_NAME = " ${prefix} -manager-container " CONTAINER_ID = $( aws ecs describe-tasks --cluster $cl --task $taskid | jq -r --arg CONTAINER_NAME $CONTAINER_NAME ' .tasks[0].containers[] | select(.name == $CONTAINER_NAME).runtimeId ' ) echo ${cl} ; \ echo ${prefix} ; \ echo ${taskarn} ; \ echo ${taskid} ; \ echo ${CONTAINER_NAME} ; echo ${CONTAINER_ID} ; aws ssm start-session --target ecs: ${prefix} _ ${taskid} _ ${CONTAINER_ID} パラメータとしてCONTAINER_IDの取得が増えておりますが、つながりました。まあ、これだけだとecs execと同じためなんのありがたさもありませんが。 なお、 AWS Fargateでのstart-session利用は AWS CLI の ソースコード を読んで得た知見であり、 AWS がサポートしている使い方ではありません。 start-session with AWS -StartPortForwardingSession では、次に、 AWS -StartPortForwardingSessionを試していきましょう。 もしできれば、接続トラブル時の切り分け作業、インターネットに公開するのに抵抗のある管理ポートへのアクセス等、いろいろ使い道があります。 #前述のおまじない aws ssm start-session --target ecs: ${prefix} _ ${taskid} _ ${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSession --parameters ' {"portNumber":["80"],"localPortNumber":["18080"]} ' ドキュメントとパラメータを追加し実行です。 ということで、つながりました。まあ、cloudshellからだと使い道がありませんが(バックグランド実行のしかたがわかりませんでした)、ローカルマシンから利用するには便利そうです。 start-session with AWS -StartPortForwardingSessionToRemoteHost では、次に、 AWS -StartPortForwardingSessionToRemoteHostを試します。 「 AWS -StartPortForwardingSessionToRemoteHost」って何?って人は、 クラスメソッド様のAWS System Managerセッションマネージャーがリモートホストのポートフォワードに対応しました をご覧ください。 ざっくりいってしまうと、session managerの対象ホストから他のホストにポート フォワ ードできる優れものです。session managerに対応していないRDSへポート フォワ ードできたりします。 これができれば、ローカルのGUIDB管理ツールからRDSへ接続が可能となります( CLI だと厳しいというメンバが一定数おりそれ用の対応検討です)。 #前述のおまじない aws ssm start-session \ --target ecs: ${prefix} _ ${taskid} _ ${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters ' {"host":["RDSエンドポイント],"portNumber":["3306"], "localPortNumber":["3306"]} ' で、実施結果ですが、、。 2022/07、2022/09で二回ほど試しておりますが、現行の AWS Fargateに入ってるエージェントバージョンが未対応とのこと。当面、ローカルからの直接RDS接続はお預けです。 番外:ECS FargateでSSMセッションマネージャーの リモートホスト のポート フォワ ード環境を構築する ECS FargateでSSMセッションマネージャーのリモートホストのポートフォワード環境を構築する にかかれているように、Fargate基盤のエージェントを利用するのではなく、ssmエージェント設定したコンテナをfargateにデプロイすれば リモートホスト へのポート フォワ ード環境の構築は可能です。 また、上記の方法以外にも、下記のような仕込みをすることで対象コンテナへのポート フォワ ードRDS接続はできそうです。 これでコンテナに[stone](https://www.gcd.org/sengoku/stone/Welcome.ja.html)でも入れておけば、Fargateのタスクを踏み台にしてデータベースなどへのアクセスができる。 参考記事: https://winebarrel.hatenablog.com/entry/2021/10/23/165720 ECS Exec with 運用 スクリプト 前述までの内容で、ポート フォワ ード、対話式でいろいろな管理オペレーションができそうということは見えてきました。 が、やはり、定型作業は単 純化 していきたいので対話式以外でのメンテナンス方式を考えていきます。 [アップデート] 実行中のコンテナに乗り込んでコマンドを実行できる「ECS Exec」が公開されました で、上の記事を見てると下記のような気になる記述が。 aws の公式ドキュメントをみてると、 /bin/sh を呼ぶ例しか書いていないのですが、任意のコマンドで呼べるんですね。 ということで、運用 スクリプト をコンテナ内に配置し呼び出してみます。 #前述のおまじない #pgdump⇒s3アップロードをしている運用スクリプトを呼び出している例 aws ecs execute-command \ --region ap-northeast-1 \ --cluster ${cl} \ --task ${taskarn} \ --container ${CONTAINER_NAME} \ --command " /bin/sh -c '/work/backup.sh backupComment' " \ --interactive #s3ダウンロード⇒pgrestoreをしている運用スクリプトを呼び出している例 aws ecs execute-command \ --region ap-northeast-1 \ --cluster ${cl} \ --task ${taskarn} \ --container ${CONTAINER_NAME} \ --command " /bin/sh -c '/work/restore.sh my-dev_20220902-153423_backupComment.dump' " \ --interactive こんな感じで、運用 スクリプト をECS Execから呼びだすことができます(なお、重い運用JOBの場合は、専用のタスクを起動した方がよいと考えております)。 ということで、既存構成に多少の手を加えることにより、ECS Execからメンテナンスをする仕組みが実装できました。 ECS Execで呼び出せるように運用 スクリプト を定義しておけば、今後下記のようなこともできそうです。 今までどおりcloudshellから Ops が手動でECS Execにて運用 スクリプト を起動する ChatOpsでECS Exec経由で運用 スクリプト を起動する チケット管理ツールのワークフローからECS Exec経由で運用 スクリプト を起動する(一部のssm run-commandはこの方式で実施しています) まとめ ということで、 AWS Fargate利用時の運用タスクの実行方法についてご紹介してみました。 執筆: @miura.toshihiko ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、美少女を高確率で出す呪文です。 Stable Diffusionで人物を出力するときに、顔が崩れている、目が変、口がない、腕(手)が変などを経験した方は多いことでしょう。NSFW(職場や学校で閲覧注意)が連続で出て、心が折れそうになった方もいることでしょう。僕もそのうちの一人です。 今回は、クオリティの高い人物画を高確率で出力し、NSFWもほとんど起きない呪文を研究しました。 v2.1 美少女アニメ画 もよろしければご覧ください。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 illustration of a beautiful girl detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust artstation, deviantart, concept art, digital painting, award-winning looking far away, shot diagonally cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose ray tracing, 8k まとめ 仲間募集 Stable Diffusionの過去コンテンツ illustration of a beautiful girl 今回もシンプルな呪文から始めましょう。徐々に呪文を足していき、その効果を確認することが呪文を学ぶには効果的です。 今回の呪文 illustration of a beautiful girl Dream Studio などの実行環境のある方は、10回ほど試してください。クオリティがバラバラなのが確認できるでしょう。今回の呪文はシンプルすぎて、出力が安定しないのです。 出力結果 detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust 今回の研究結果で最も重要なのが、これらの呪文。人物の出力を安定させるには、detailedで、体のパーツを指定します。 armsを指定することで、腕が変になることがだいぶ減りました。 detailedを指定すると、Stable Diffusionは指定された部分をクローズアップしようとします。今回は、顔のパーツを多く指定しているため、必然的に顔がクローズアップされます。顔がクローズアップされた画像は、バリエーションが出しにくいため、単調なものになりがちです。それを少しでも緩和するために、bust(胸)を指定しています。 detailed waist(腰)も指定してみましたが、あまり効果がないのと、NSFWが起きる確率が増えるため、呪文にいれませんでした。 detailed legs(脚)も指定してみましたが、NSFWが頻繁に起きるので、呪文にいれませんでした。 detailed body(体)も指定してみましたが、効果が感じられなかったので、呪文にいれませんでした。 detailed skin(肌)も指定してみましたが、ときどきノイズがのるので、呪文にいれませんでした。 detailed eyelashes(まつげ)も指定してみましたが、ときどきノイズがのる(目の下にもまつげが出たりする)ので、呪文にいれませんでした。 detailed eyebrows(眉毛)も指定してみましたが、不自然に強調されているように感じることがあったので、呪文にいれませんでした。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust Dream Studio などの実行環境のある方は、10回ほど試してください。変な画像が出力されることはなくなったと思います。ただし、クオリティは安定してませんね。 出力結果 artstation, deviantart , concept art, digital painting, award-winning クオリティを安定させるためには、作風を指定することが重要です。イラストの投稿サイトとして、artstation, deviantart を指定します。concept art, digital painting, award-winningは、お決まりの呪文です。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, artstation, deviantart, concept art, digital painting, award-winning 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, artstation, deviantart, concept art, digital painting, award-winning Dream Studio などの実行環境のある方は、10回ほど試してください。クオリティも安定してきましたね。 出力結果 looking far away, shot diagonally すでに人物画のクオリティは、かなり上がっていますが、正面を見ている構図が多く、単調になりがちです。目線を正面から外してみましょう。looking far away(遠くを見る)を指定します。 shot diagonally(斜めから撮る)で、撮影の角度に変化をつけましょう。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning 出力結果 だいぶ雰囲気が出てきたのではないでしょうか。 cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose 画像のクオリティを上げるには、シーン(scene)、構図(composition)、ライティング(lighting)を指定することが重要です。魔法の呪文、cinematicをつけておきましょう。 cinematic postprocessing, overexposeでさらにクオリティを向上させます。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed beautiful eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed beautiful eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose 出力結果 キラキラして映画の1シーンのようですね。 ただし、この呪文から、再現度は低くなります。いつも映画のような1シーンになるわけではないということです。 ray tracing, 8k 先程の呪文で完成にしてもよいのですが、もう少し、フォトリアルにしたい場合は、ray tracing, 8kの呪文を追加します。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 出力結果 まとめ 今回は、クオリティの高い人物画を高確率で出力する方法を紹介しました。 顔がクローズアップされ、正面を向いている画像は、ありきたりな感じになるリスクがあります。変化をつける呪文を学びましょう。 次回は、 長い呪文は切り捨てられる編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、美少女を高確率で出す呪文です。 Stable Diffusionで人物を出力するときに、顔が崩れている、目が変、口がない、腕(手)が変などを経験した方は多いことでしょう。NSFW(職場や学校で閲覧注意)が連続で出て、心が折れそうになった方もいることでしょう。僕もそのうちの一人です。 今回は、クオリティの高い人物画を高確率で出力し、NSFWもほとんど起きない呪文を研究しました。 v2.1 美少女アニメ画 もよろしければご覧ください。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 illustration of a beautiful girl detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust artstation, deviantart, concept art, digital painting, award-winning looking far away, shot diagonally cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose ray tracing, 8k まとめ 仲間募集 Stable Diffusionの過去コンテンツ illustration of a beautiful girl 今回もシンプルな呪文から始めましょう。徐々に呪文を足していき、その効果を確認することが呪文を学ぶには効果的です。 今回の呪文 illustration of a beautiful girl Dream Studio などの実行環境のある方は、10回ほど試してください。クオリティがバラバラなのが確認できるでしょう。今回の呪文はシンプルすぎて、出力が安定しないのです。 出力結果 detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust 今回の研究結果で最も重要なのが、これらの呪文。人物の出力を安定させるには、detailedで、体のパーツを指定します。 armsを指定することで、腕が変になることがだいぶ減りました。 detailedを指定すると、Stable Diffusionは指定された部分をクローズアップしようとします。今回は、顔のパーツを多く指定しているため、必然的に顔がクローズアップされます。顔がクローズアップされた画像は、バリエーションが出しにくいため、単調なものになりがちです。それを少しでも緩和するために、bust(胸)を指定しています。 detailed waist(腰)も指定してみましたが、あまり効果がないのと、NSFWが起きる確率が増えるため、呪文にいれませんでした。 detailed legs(脚)も指定してみましたが、NSFWが頻繁に起きるので、呪文にいれませんでした。 detailed body(体)も指定してみましたが、効果が感じられなかったので、呪文にいれませんでした。 detailed skin(肌)も指定してみましたが、ときどきノイズがのるので、呪文にいれませんでした。 detailed eyelashes(まつげ)も指定してみましたが、ときどきノイズがのる(目の下にもまつげが出たりする)ので、呪文にいれませんでした。 detailed eyebrows(眉毛)も指定してみましたが、不自然に強調されているように感じることがあったので、呪文にいれませんでした。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust Dream Studio などの実行環境のある方は、10回ほど試してください。変な画像が出力されることはなくなったと思います。ただし、クオリティは安定してませんね。 出力結果 artstation, deviantart , concept art, digital painting, award-winning クオリティを安定させるためには、作風を指定することが重要です。イラストの投稿サイトとして、artstation, deviantart を指定します。concept art, digital painting, award-winningは、お決まりの呪文です。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, artstation, deviantart, concept art, digital painting, award-winning 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, artstation, deviantart, concept art, digital painting, award-winning Dream Studio などの実行環境のある方は、10回ほど試してください。クオリティも安定してきましたね。 出力結果 looking far away, shot diagonally すでに人物画のクオリティは、かなり上がっていますが、正面を見ている構図が多く、単調になりがちです。目線を正面から外してみましょう。looking far away(遠くを見る)を指定します。 shot diagonally(斜めから撮る)で、撮影の角度に変化をつけましょう。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning 出力結果 だいぶ雰囲気が出てきたのではないでしょうか。 cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose 画像のクオリティを上げるには、シーン(scene)、構図(composition)、ライティング(lighting)を指定することが重要です。魔法の呪文、cinematicをつけておきましょう。 cinematic postprocessing, overexposeでさらにクオリティを向上させます。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed beautiful eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed beautiful eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose 出力結果 キラキラして映画の1シーンのようですね。 ただし、この呪文から、再現度は低くなります。いつも映画のような1シーンになるわけではないということです。 ray tracing, 8k 先程の呪文で完成にしてもよいのですが、もう少し、フォトリアルにしたい場合は、ray tracing, 8kの呪文を追加します。 今回の呪文(横長、コピー&ペースト用) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 閲覧用呪文(改行版) illustration of a beautiful girl, detailed beautiful face, detailed hair, detailed human eyes, detailed mouth, detailed arms, detailed bust, looking far away, shot diagonally, artstation, deviantart, concept art, digital painting, award-winning, cinematic postprocessing, cinematic scene, cinematic composition, cinematic lighting, overexpose, ray tracing, 8k 出力結果 まとめ 今回は、クオリティの高い人物画を高確率で出力する方法を紹介しました。 顔がクローズアップされ、正面を向いている画像は、ありきたりな感じになるリスクがあります。変化をつける呪文を学びましょう。 次回は、 長い呪文は切り捨てられる編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
論文読み会の紹介 こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター の山下です。 今回は、X イノベーション 本部の有志(現在はソフトウェアデザインセンターとINNOLABが中心)で実施している論文読み会について紹介しようと思います。 毎月1回、担当を決めて担当の方が読みたい論文を選んで、それをスライドなどに内容をまとめて紹介するスタイルで実施しています。 当日みんなで集まって論文を読み進める形式ではないです。 ISIDはいわゆる SIer と呼ばれる業態の会社ですが、読む論文は特に情報関係の論文に限っていません。 ソフトウェア工学 の論文やDNAストレージの論文など色々な論文を選んで輪読しています。 論文輪読会の目的とメリット 論文読み会は、自分が入社した時(2021年10月)に部内で論文を一緒に読むような仲間が欲しくて回りに声を掛けて始めた活動です。 最初は自分のチーム内くらいの規模からやるかと思っていたところ、せっかくなので他の部門ともやろうということになりINNOLABの方と共同でやろうということになって始まりました。 自分は論文を読むことはいくつかメリットがあると思っていて、まず論文自体に書いてある技術の知識が身につくということがあります。それ以外にも、メリットがあると考えているので簡単に紹介します。 自分の興味がある分野が分かってくる 多様な分野の論文を探す経験や関連する分野を見ていると自分が興味がある分野が分かってきたりします。 技術調査を行なう経験が積める 論文を読むためにはその技術に関する周辺の知識やその技術が生まれた経緯なども含めて色々調査が必要となったりします。これは流行っている技術を勉強する場合には必ずしも必要がない行為です。例えば、特定のWebの技術(Reactなど)を知りたい場合はその技術について解説した書籍があったり、 google で検索すると解説してくれている記事などもたくさん公開されています。しかし、論文に載っている内容は、まだ世間に広まっていない技術であったりすることも少なくないです。こういった調査になれていることで、流行しはじめたばかりの技術や特定領域でのみ利用されている技術の調査する場合に経験が活かせたりします。 人に技術を紹介する経験 自分の興味に基づいて技術を紹介する機会というのは意外と少ないものです。 業務上で技術を選ぶ場合は実用性などの観点で技術選定を行なうことがほとんどでしょう。 そんな自分が気になる技術を人に紹介するので面白く紹介しようと思って色々工夫したくなるのでプレゼンの練習にもなります。 新たな技術分野を知れる ここまでは、論文を紹介する側のメリットが並んでいますが、これは聞く側のメリットです。 今回実施している論文輪読会は読む論文の対象分野を絞っていません。ですので、今まで興味を持っていなかった分野に触れることが出来、見聞が広まる機会に繋っています。 現在開催している範囲でも以下のような多様な分野の論文が紹介されました。 ソフトウェア工学 DNAストレージ 深層学習 Human Computer Interaction関連 人間科学 本当に多様な論文を紹介して貰えて毎回楽しみです。 論文輪読会の実施に掛かる費用 論文といえば学会から購読するのが一般的です。しかし、論文は無料で読めるものが最近だと多いです。 arxiv ( https://arxiv.org/ )などが有名ですね。 とはいえ、有名な学会などの査読付きの論文などはやはり有償のものとなっているものが多いです。 情報系であれば、 ACM や IEEE の学会の論文を読める環境の方が良いと思います。 大人数で論文を読むのであれば、企業として契約することを検討した方が良いのですが 今回は少人数ということだったので、希望者が個別に ACM などを購読する形で実施しています。 自分は会社が論文購読の費用( ACM で$198/year)を負担してくれるので大変助かりました。 開催しているときの雰囲気など これまでに、2022年の3月から毎月開催していて5回実施しています。 概ね好評だと考えています(特にアンケートなどを取っていないので雰囲気です)。 毎回、新しい分野の新しい論文を発表者の方が選んでくれていて大変面白い会合となっています。 聞いている参加者の方も様々な観点で質問を出してくれて、色々刺激になっているのではと思っております。 まとめ 今回はX イノベーション 本部で実施している論文読み会について紹介しました。是非皆さんの会社などでも実施してみてはいかがでしょうか?最近は論文を読む敷居もDeepLや Google翻訳 といった翻訳ツールもあってとても手軽に読めるようになりました。いい時代になりましたね。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募お待ちしています。 ソリューションアーキテクト 執筆: @yamashita.tsuyoshi 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
論文読み会の紹介 こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター の山下です。 今回は、X イノベーション 本部の有志(現在はソフトウェアデザインセンターとINNOLABが中心)で実施している論文読み会について紹介しようと思います。 毎月1回、担当を決めて担当の方が読みたい論文を選んで、それをスライドなどに内容をまとめて紹介するスタイルで実施しています。 当日みんなで集まって論文を読み進める形式ではないです。 ISIDはいわゆる SIer と呼ばれる業態の会社ですが、読む論文は特に情報関係の論文に限っていません。 ソフトウェア工学 の論文やDNAストレージの論文など色々な論文を選んで輪読しています。 論文輪読会の目的とメリット 論文読み会は、自分が入社した時(2021年10月)に部内で論文を一緒に読むような仲間が欲しくて回りに声を掛けて始めた活動です。 最初は自分のチーム内くらいの規模からやるかと思っていたところ、せっかくなので他の部門ともやろうということになりINNOLABの方と共同でやろうということになって始まりました。 自分は論文を読むことはいくつかメリットがあると思っていて、まず論文自体に書いてある技術の知識が身につくということがあります。それ以外にも、メリットがあると考えているので簡単に紹介します。 自分の興味がある分野が分かってくる 多様な分野の論文を探す経験や関連する分野を見ていると自分が興味がある分野が分かってきたりします。 技術調査を行なう経験が積める 論文を読むためにはその技術に関する周辺の知識やその技術が生まれた経緯なども含めて色々調査が必要となったりします。これは流行っている技術を勉強する場合には必ずしも必要がない行為です。例えば、特定のWebの技術(Reactなど)を知りたい場合はその技術について解説した書籍があったり、 google で検索すると解説してくれている記事などもたくさん公開されています。しかし、論文に載っている内容は、まだ世間に広まっていない技術であったりすることも少なくないです。こういった調査になれていることで、流行しはじめたばかりの技術や特定領域でのみ利用されている技術の調査する場合に経験が活かせたりします。 人に技術を紹介する経験 自分の興味に基づいて技術を紹介する機会というのは意外と少ないものです。 業務上で技術を選ぶ場合は実用性などの観点で技術選定を行なうことがほとんどでしょう。 そんな自分が気になる技術を人に紹介するので面白く紹介しようと思って色々工夫したくなるのでプレゼンの練習にもなります。 新たな技術分野を知れる ここまでは、論文を紹介する側のメリットが並んでいますが、これは聞く側のメリットです。 今回実施している論文輪読会は読む論文の対象分野を絞っていません。ですので、今まで興味を持っていなかった分野に触れることが出来、見聞が広まる機会に繋っています。 現在開催している範囲でも以下のような多様な分野の論文が紹介されました。 ソフトウェア工学 DNAストレージ 深層学習 Human Computer Interaction関連 人間科学 本当に多様な論文を紹介して貰えて毎回楽しみです。 論文輪読会の実施に掛かる費用 論文といえば学会から購読するのが一般的です。しかし、論文は無料で読めるものが最近だと多いです。 arxiv ( https://arxiv.org/ )などが有名ですね。 とはいえ、有名な学会などの査読付きの論文などはやはり有償のものとなっているものが多いです。 情報系であれば、 ACM や IEEE の学会の論文を読める環境の方が良いと思います。 大人数で論文を読むのであれば、企業として契約することを検討した方が良いのですが 今回は少人数ということだったので、希望者が個別に ACM などを購読する形で実施しています。 自分は会社が論文購読の費用( ACM で$198/year)を負担してくれるので大変助かりました。 開催しているときの雰囲気など これまでに、2022年の3月から毎月開催していて5回実施しています。 概ね好評だと考えています(特にアンケートなどを取っていないので雰囲気です)。 毎回、新しい分野の新しい論文を発表者の方が選んでくれていて大変面白い会合となっています。 聞いている参加者の方も様々な観点で質問を出してくれて、色々刺激になっているのではと思っております。 まとめ 今回はX イノベーション 本部で実施している論文読み会について紹介しました。是非皆さんの会社などでも実施してみてはいかがでしょうか?最近は論文を読む敷居もDeepLや Google翻訳 といった翻訳ツールもあってとても手軽に読めるようになりました。いい時代になりましたね。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募お待ちしています。 ソリューションアーキテクト 執筆: @yamashita.tsuyoshi 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
こんにちは。ISID CIT事業部の熊倉です。 本記事では、 Salesforce の Summer'21アップデートで正式リリース となったExperience Cloudの新しいテンプレート 『Build Your Own (LWR) テンプレート』 について紹介したいと思います。 Experience Cloud は Salesforce が提供しているWebサイトを構築できるサービスで、カスタマーサイトやFAQサイトといった Salesforce の他サービス(主にService Cloudですね)と親和性の高いサイトを構築できます。 特長として、ポイントアンドクリックで必要な設定を完結できるテンプレートがあらかじめ多数提供されていることが挙げられます。 1. Build Your Own (LWR) テンプレート 1.1 Lightning Web Runtime (LWR) の紹介 1.2 Build Your Own (LWR) テンプレートとは Auraサイト / LWRサイト という呼称について 1.3 Build Your Own (LWR) テンプレートのメリット、デメリット メリット デメリット 1.4 ユースケース ● Auraテンプレートのユースケースから逸れたサイト ● 高度なデザインを求められるWebサイト ● 不特定多数のユーザーが訪れるようなランディングページ 2. Build Your Own (LWR) テンプレートを使ってみた 2.1 SLDSデザインを削除する 1. ヘッダーを編集 2. LWCを作成 3. 確認 3. まとめ 1. Build Your Own (LWR) テンプレート Experience Cloudは簡単にWebサイトの構築ができる反面、カスタマイズ性の低さが弱点でした。 もし、カスタマーサイトやFAQサイトといった ユースケース 以外のサイトを構築しようとしたり、複雑なデザイン要件を叶えようとした場合、途端にハードルが上がってしまうことがありました。 そこで『Build Your Own (LWR) テンプレート』の登場です。 Build Your Own (LWR) テンプレートは従来のExperience Cloudのテンプレートと大きく思想が異なり、最小限のページや コンポーネント のみ提供され、サイトに必要なページや コンポーネント は自分達で開発する(Build Your Own)必要があります。 そのため、従来のテンプレートに比べ、 カスタマイズ性が非常に高いという特徴を持っています。 テンプレートの説明に入る前にBuild Your Own ( LWR ) テンプレートの LWR について、まず紹介をしたいと思います。 1.1 Lightning Web Runtime (LWR) の紹介 LWRとはLightning Web Runtimeの略で、 Salesforce が提供する新しいWebフレームワークです( OSS 版は現在Developer Preview ) 特徴として以下の3つが掲げられています。 https://developer.salesforce.com/docs/platform/lwr/overview Performance Our bar is set at subsecond full page loads. Friction-Free Enjoyable local development experience. Power All the power of Lightning Web Components and the Salesforce platform at your disposal. 端的にまとめると 「高パフォーマンスなWebサイトを(※)Lightning Web Componentで開発できる デベロッパ ーフレンドリーな」 フレームワーク といったところです。 LWRはHerokuの インスタンス 等のNode.js 実行環境下で動作し、静的なコンテンツを配信したりSPAを構築できます。 ※ Lightning Web Component (LWC) とは Salesforce で コンポーネント を作成する際のプログラミングモデルです。LWCが登場する前はAuraというプログラミングモデルに則る必要がありました。 1.2 Build Your Own (LWR) テンプレートとは LWRを使用することで高パフォーマンスなWebサイトを構築できますが、Node.jsが動作するサーバの用意といったインフラの準備が必要です。 そこで、 Salesforce 環境で ホスティング されるExperience CloudでもLWRを利用できるようにしたのが『Build Your Own (LWR) テンプレート』となります。(他にも『マイ クロサイ ト(LWR)』というテンプレートも用意されています) Build Your Own (LWR) テンプレートを利用することで、上記の高パフォーマンスといったメリットを受けることができますが、反対に コンポーネント の開発方法がLWCに限定される(Aura はNG) という制約もついています。 Auraサイト / LWRサイト という呼称について ちなみに、LWRを使用したテンプレートが公開されたことにより、従来のテンプレートやそれを利用して公開されたサイトはAuraテンプレート、Auraサイトと呼ばれるようになりました。 https://help.salesforce.com/s/articleView?id=sf.exp_cloud_plan_frameworks.htm&type=5 Aura テンプレートには、 カスタマーサービス 、Partner Central、ヘルプセンター、Build Your Own、カスタマー取引先ポータルが含まれます。Aura テンプレートはほぼローコード (low-code) です。Lightning Web コンポーネント と Aura コンポーネント は 1 つのページで共存および相互運用できます。 https://help.salesforce.com/s/articleView?id=release-notes.rn_experiences.htm&type=5&release=234 LWR サイトは、Build Your Own (LWR) テンプレートなど、最新の LWR ベースのテンプレートを使用して構築されます。 Aura サイトは、 カスタマーサービス 、Partner Central、カスタマー取引先ポータルなど、Aura で実行されるオリジナルのテンプレートを使用して構築されます。 1.3 Build Your Own (LWR) テンプレートのメリット、デメリット Build Your Own (LWR) テンプレートのメリット、デメリットを以下に記載します。 メリット LWRを利用するため、高パフォーマンスの恩恵を受けられる ビルド時にあらかじめサイトのコンテンツが生成(SSG)されます 初回のリク エス ト時にHTTPキャッシュされ、2回目以降のリク エス トがさらに高速に動作します 認証が不要なサイトを構築する際、URLに「/s」を含ませないことが可能 Auraテンプレートで構築したWebサイトの場合、 ドメイン 下に『/s』が含まれてしまいますが(例: https://my-domain.my.site.com/s/ )、Build Your Own (LWR) テンプレートを使用することで認証が不要のサイトの場合『/s』を含ませないことが可能になりました ちなみに現在(2022年8月)だと認証が必要なサイトの場合は『/s』が含まれてしまうのですが、 Winter'23のアップデートで認証が必要なサイトの場合でも『/s』が含まれなくなるようです URLが煩雑になるのを避け、サイトの ブランディング に良い影響を与えることができます headタグを(Auraテンプレートと比較して)自由に編集できる Auraテンプレートでは制限があったheadタグを(比較して)自由に編集できるようになりました 編集可能になったことにより、次のようなことが実現可能になりました Salesforce の スタイルシート を削除する(後述) サードパーティ のjsライブラリを利用する Google Analytics や Google Tag Managerを使用可能 Examples: Use Google Analytics in LWR Sites Examples: Use Google Tag Manager in LWR Sites デメリット ほとんどの画面で開発が必要 Auraテンプレートで使用できる コンポーネント (レコードの内容を表示するといった標準 コンポーネント )が使用できません Build Your Ownの名の通り、 コンポーネント を自前で作成する必要があります 開発スキルとしてLWCが必須なため、LWCを学習するコストがかかる LWRを利用している関係上、LWCでのみ開発が可能で、Aura コンポーネント は利用不可となっています。 1.4 ユースケース 以下のような ユースケース を実現したい場合、LWR テンプレートの使用がマッチします。 ● Auraテンプレートの ユースケース から逸れたサイト カスタマー ポータルサイト やQAサイト、お問い合わせフォームといったWebサイトを構築する場合、従来のテンプレートを利用するのが便利かと思います。しかし、それ以外を目的としたサイトをExperience Cloudで構築したいとなった場合、カスタマイズ性の低さが開発のハードルになってしまうことがままあります。その場合、LWR テンプレートは選択肢になると思います。 ● 高度なデザインを求められるWebサイト 上記の内容とも被りますが、高度なデザインが求められる場合でもLWR テンプレートは選択肢になると思います。 カスタマイズ性が上がったことで、従来のテンプレートでは表現しきれないデザインの実現が可能になりました。 この後、具体的に記述しますが、 Salesforce でネイティブに利用されているデザインシステムであるSLDSを完全に削除することも可能です。代わりに有名な CSS フレームワーク を利用することもできますので、Web上にある CSS のノウハウをExperiece Cloudで構築したサイトで活用できるのもメリットと言えるかと思います。 ● 不特定多数のユーザーが訪れるようなランディングページ LWRの高いパフォーマンス性を活かして、不特定多数のユーザーが訪れるようなランディングページといったワンショットのサイト公開にも最適です。 Google Analytics や Google Tag Managerを利用し、利用者の分析を行うことも可能です。(この場合、 Build Your Own (LWR)テンプレートと同様にLWRを利用している マイクロサイト というテンプレート が最適な選択肢になるかと思います) 2. Build Your Own (LWR) テンプレートを使ってみた これまでBuild Your Own (LWR) テンプレートについて紹介してきましたが、これから実際にテンプレートを利用した開発について紹介していきたいと思います! Build Your Own (LWR) テンプレートのユニークな機能(Auraテンプレートでは不可能な機能)は たくさん あるのですが、今回は「SLDSデザインを削除できる」機能をピックアップして紹介します。 LWR テンプレートの機能について詳しく知りたい方は以下のドキュメントを参考にしてください。 https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/intro.htm また、LWRについてのドキュメントや サンプルソース といったリソースがまとめられたページも用意されていますので1からキャッチアップしたい方は参考になるかと思います。 https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/intro_resources.htm (個人的には サンプルアプリケーションのデプロイ と YouTubeのコンテンツ がキャッチアップに大変有用だったのでオススメです!) 2.1 SLDSデザインを削除する それでは「ヘッダーからSLDSの削除」を試してみたいと思います。 SLDSとは Salesforce Design System の略で、 Salesforce が公開しているデザインシステムです。Aura テンプレートでは標準でロードされており削除が難しかったのですが、LWR テンプレートでは コメントアウト することで完全に削除できます。 SLDSを削除することで、 デザイン面について完全にコン トロール 下におくことができます。 今回は、SLDSを削除し、代わりに CSS フレームワーク の Bulma を利用するケースを検証していきたいと思います。 サンプルソース として、公式から提供されている次のソースをLWC化して取り込んでみたいと思います。 https://bulmatemplates.github.io/bulma-templates/templates/admin.html ( サンプルソース ではBulmaの他に「Font Awesome 」「 Google Fonts」を利用していましたので以下検証でもロードしたいと思います) 1. ヘッダーを編集 Experience Cloudのビルダーページから 設定 > 詳細 > ヘッドマーク アップを編集 でヘッダーを編集します。 デフォルトで用意されているヘッダーは次の画像のようになっています。(LWRテンプレートはAuraテンプレートに比べて編集可能な箇所が多いです) 次のタグがSLDSのロード箇所になりますので、 コメントアウト します https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/brand_remove.htm < link rel = "stylesheet" href = "{ basePath }/assets/styles/salesforce-lightning-design-system.min.css?{ versionKey }" /> ちなみに < link rel = "stylesheet" href = "{ basePath }/assets/styles/dxp-site-spacing-styling-hooks.min.css?{ versionKey }" /> < link rel = "stylesheet" href = "{ basePath }/assets/styles/dxp-styling-hooks.min.css?{ versionKey }" /> < link rel = "stylesheet" href = "{ basePath }/assets/styles/dxp-slds-extensions.min.css?{ versionKey }" /> の箇所は、--dxp Styling Hooksと呼ばれる機能を反映させるための CSS になります。 https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/brand_start_using.htm --dxp Styling Hooksとは CSS カスタムプロパティを使用し、左サイドにあるテーマパネルからボタンやリンクといったHTML要素のデザインをページ全体で一括で編集できる仕組みになります。 Styling Hookは使用しない!という方は コメントアウト しても良いかと思います。(今回は一旦そのまま残しておきます) 続いて、以下 サンプルソース の <head> 内の記述から、 https://github.com/BulmaTemplates/bulma-templates/blob/master/templates/admin.html Bulma、Font Awesome 、 Google Fontsをロードするタグを追加します。 < link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" > < link rel = "stylesheet" href = "https://fonts.googleapis.com/css?family=Open+Sans:300,400,700" > < link rel = "stylesheet" href = "https://unpkg.com/bulma@0.9.0/css/bulma.min.css" /> (hrefのリンクについては Salesforce の「設定」 >「CSP 信頼済みサイト」 から登録を行います) ここまででヘッダーの記述は以下のようになっているかと思います 2. LWCを作成 ヘッダーでSLDSを削除し各ソースをロードできたので、続いてLWCを作成します。 まず、以下 サンプルソース から <body> 内の記述をそのままLWCのHTMLにコピーします。 https://github.com/BulmaTemplates/bulma-templates/blob/master/templates/admin.html 次に、以下 サンプルソース からLWCの CSS にコピーします。 https://github.com/BulmaTemplates/bulma-templates/blob/master/css/admin.css ただし、 html,body { } の箇所に関しては コンポーネント の範囲外となってしまうため、ヘッダー側に記述をしました。 3. 確認 さて、LWCがいよいよ完成したので、サイトを公開しコンテンツを確認してみたいと思います! ■ Build Your Own (LWR) ページ ■ サンプルサイト( https://bulmatemplates.github.io/bulma-templates/templates/admin.html ) いかがでしょうか? SLDSが削除されていること、Bulmaが正常にロードされていることが確認できるかと思います。 また、カード内の文章に「 Google Fonts」、検索欄に「Font Awesome 」が利用されていますが、こちらも正常に描写されていることがわかるかと思います。 ちなみに「ページ上左右のスペース」や「ボタンやリンク」のデザインが異なるかと思いますが、こちらは前述の --dxp Styling Hook が影響しており、ヘッダーから コメントアウト すると以下のようなサイトになります。 ( ピクセル パーフェクト!) 3. まとめ ここまで読んでいただきありがとうございました。 本記事がBuid Your Own (LWR) テンプレートについて理解の一助になれば幸いです。 今回、機能の紹介では「SLDSの削除」について取り上げましたが、他にも「多言語対応」「特権 スクリプト を使用した サードパーティ 製JSライブラリの利用」「LWRテンプレートのみ利用できるExperience Builderの コンポーネント 」「Salesfroce CMS との連携」等々、LWR テンプレートのユニークな機能は たくさん あります。 是非、公式ドキュメントを読んでいただき、その他の機能についてもキャッチアップしていただけると幸いです。 本記事ではLWR テンプレート利用によるWebフロントエンドの効果について主に紹介しましたが、バックエンドが Salesforce で統合されていることも大きなメリットとなります。弊社ではLWR テンプレートを利用したWebサイト開発の実績もありますので、 デザイン性が高く、高速・安全なWebサイトを フル Salesforce で実現したい方は是非ご相談ください! 執筆: @kumakura.koki.isid 、レビュー: @higa ( Shodo で執筆されました )
アバター
こんにちは。ISID CIT事業部の熊倉です。 本記事では、 Salesforce の Summer'21アップデートで正式リリース となったExperience Cloudの新しいテンプレート 『Build Your Own (LWR) テンプレート』 について紹介したいと思います。 Experience Cloud は Salesforce が提供しているWebサイトを構築できるサービスで、カスタマーサイトやFAQサイトといった Salesforce の他サービス(主にService Cloudですね)と親和性の高いサイトを構築できます。 特長として、ポイントアンドクリックで必要な設定を完結できるテンプレートがあらかじめ多数提供されていることが挙げられます。 1. Build Your Own (LWR) テンプレート 1.1 Lightning Web Runtime (LWR) の紹介 1.2 Build Your Own (LWR) テンプレートとは Auraサイト / LWRサイト という呼称について 1.3 Build Your Own (LWR) テンプレートのメリット、デメリット メリット デメリット 1.4 ユースケース ● Auraテンプレートのユースケースから逸れたサイト ● 高度なデザインを求められるWebサイト ● 不特定多数のユーザーが訪れるようなランディングページ 2. Build Your Own (LWR) テンプレートを使ってみた 2.1 SLDSデザインを削除する 1. ヘッダーを編集 2. LWCを作成 3. 確認 3. まとめ 1. Build Your Own (LWR) テンプレート Experience Cloudは簡単にWebサイトの構築ができる反面、カスタマイズ性の低さが弱点でした。 もし、カスタマーサイトやFAQサイトといった ユースケース 以外のサイトを構築しようとしたり、複雑なデザイン要件を叶えようとした場合、途端にハードルが上がってしまうことがありました。 そこで『Build Your Own (LWR) テンプレート』の登場です。 Build Your Own (LWR) テンプレートは従来のExperience Cloudのテンプレートと大きく思想が異なり、最小限のページや コンポーネント のみ提供され、サイトに必要なページや コンポーネント は自分達で開発する(Build Your Own)必要があります。 そのため、従来のテンプレートに比べ、 カスタマイズ性が非常に高いという特徴を持っています。 テンプレートの説明に入る前にBuild Your Own ( LWR ) テンプレートの LWR について、まず紹介をしたいと思います。 1.1 Lightning Web Runtime (LWR) の紹介 LWRとはLightning Web Runtimeの略で、 Salesforce が提供する新しいWebフレームワークです( OSS 版は現在Developer Preview ) 特徴として以下の3つが掲げられています。 https://developer.salesforce.com/docs/platform/lwr/overview Performance Our bar is set at subsecond full page loads. Friction-Free Enjoyable local development experience. Power All the power of Lightning Web Components and the Salesforce platform at your disposal. 端的にまとめると 「高パフォーマンスなWebサイトを(※)Lightning Web Componentで開発できる デベロッパ ーフレンドリーな」 フレームワーク といったところです。 LWRはHerokuの インスタンス 等のNode.js 実行環境下で動作し、静的なコンテンツを配信したりSPAを構築できます。 ※ Lightning Web Component (LWC) とは Salesforce で コンポーネント を作成する際のプログラミングモデルです。LWCが登場する前はAuraというプログラミングモデルに則る必要がありました。 1.2 Build Your Own (LWR) テンプレートとは LWRを使用することで高パフォーマンスなWebサイトを構築できますが、Node.jsが動作するサーバの用意といったインフラの準備が必要です。 そこで、 Salesforce 環境で ホスティング されるExperience CloudでもLWRを利用できるようにしたのが『Build Your Own (LWR) テンプレート』となります。(他にも『マイ クロサイ ト(LWR)』というテンプレートも用意されています) Build Your Own (LWR) テンプレートを利用することで、上記の高パフォーマンスといったメリットを受けることができますが、反対に コンポーネント の開発方法がLWCに限定される(Aura はNG) という制約もついています。 Auraサイト / LWRサイト という呼称について ちなみに、LWRを使用したテンプレートが公開されたことにより、従来のテンプレートやそれを利用して公開されたサイトはAuraテンプレート、Auraサイトと呼ばれるようになりました。 https://help.salesforce.com/s/articleView?id=sf.exp_cloud_plan_frameworks.htm&type=5 Aura テンプレートには、 カスタマーサービス 、Partner Central、ヘルプセンター、Build Your Own、カスタマー取引先ポータルが含まれます。Aura テンプレートはほぼローコード (low-code) です。Lightning Web コンポーネント と Aura コンポーネント は 1 つのページで共存および相互運用できます。 https://help.salesforce.com/s/articleView?id=release-notes.rn_experiences.htm&type=5&release=234 LWR サイトは、Build Your Own (LWR) テンプレートなど、最新の LWR ベースのテンプレートを使用して構築されます。 Aura サイトは、 カスタマーサービス 、Partner Central、カスタマー取引先ポータルなど、Aura で実行されるオリジナルのテンプレートを使用して構築されます。 1.3 Build Your Own (LWR) テンプレートのメリット、デメリット Build Your Own (LWR) テンプレートのメリット、デメリットを以下に記載します。 メリット LWRを利用するため、高パフォーマンスの恩恵を受けられる ビルド時にあらかじめサイトのコンテンツが生成(SSG)されます 初回のリク エス ト時にHTTPキャッシュされ、2回目以降のリク エス トがさらに高速に動作します 認証が不要なサイトを構築する際、URLに「/s」を含ませないことが可能 Auraテンプレートで構築したWebサイトの場合、 ドメイン 下に『/s』が含まれてしまいますが(例: https://my-domain.my.site.com/s/ )、Build Your Own (LWR) テンプレートを使用することで認証が不要のサイトの場合『/s』を含ませないことが可能になりました ちなみに現在(2022年8月)だと認証が必要なサイトの場合は『/s』が含まれてしまうのですが、 Winter'23のアップデートで認証が必要なサイトの場合でも『/s』が含まれなくなるようです URLが煩雑になるのを避け、サイトの ブランディング に良い影響を与えることができます headタグを(Auraテンプレートと比較して)自由に編集できる Auraテンプレートでは制限があったheadタグを(比較して)自由に編集できるようになりました 編集可能になったことにより、次のようなことが実現可能になりました Salesforce の スタイルシート を削除する(後述) サードパーティ のjsライブラリを利用する Google Analytics や Google Tag Managerを使用可能 Examples: Use Google Analytics in LWR Sites Examples: Use Google Tag Manager in LWR Sites デメリット ほとんどの画面で開発が必要 Auraテンプレートで使用できる コンポーネント (レコードの内容を表示するといった標準 コンポーネント )が使用できません Build Your Ownの名の通り、 コンポーネント を自前で作成する必要があります 開発スキルとしてLWCが必須なため、LWCを学習するコストがかかる LWRを利用している関係上、LWCでのみ開発が可能で、Aura コンポーネント は利用不可となっています。 1.4 ユースケース 以下のような ユースケース を実現したい場合、LWR テンプレートの使用がマッチします。 ● Auraテンプレートの ユースケース から逸れたサイト カスタマー ポータルサイト やQAサイト、お問い合わせフォームといったWebサイトを構築する場合、従来のテンプレートを利用するのが便利かと思います。しかし、それ以外を目的としたサイトをExperience Cloudで構築したいとなった場合、カスタマイズ性の低さが開発のハードルになってしまうことがままあります。その場合、LWR テンプレートは選択肢になると思います。 ● 高度なデザインを求められるWebサイト 上記の内容とも被りますが、高度なデザインが求められる場合でもLWR テンプレートは選択肢になると思います。 カスタマイズ性が上がったことで、従来のテンプレートでは表現しきれないデザインの実現が可能になりました。 この後、具体的に記述しますが、 Salesforce でネイティブに利用されているデザインシステムであるSLDSを完全に削除することも可能です。代わりに有名な CSS フレームワーク を利用することもできますので、Web上にある CSS のノウハウをExperiece Cloudで構築したサイトで活用できるのもメリットと言えるかと思います。 ● 不特定多数のユーザーが訪れるようなランディングページ LWRの高いパフォーマンス性を活かして、不特定多数のユーザーが訪れるようなランディングページといったワンショットのサイト公開にも最適です。 Google Analytics や Google Tag Managerを利用し、利用者の分析を行うことも可能です。(この場合、 Build Your Own (LWR)テンプレートと同様にLWRを利用している マイクロサイト というテンプレート が最適な選択肢になるかと思います) 2. Build Your Own (LWR) テンプレートを使ってみた これまでBuild Your Own (LWR) テンプレートについて紹介してきましたが、これから実際にテンプレートを利用した開発について紹介していきたいと思います! Build Your Own (LWR) テンプレートのユニークな機能(Auraテンプレートでは不可能な機能)は たくさん あるのですが、今回は「SLDSデザインを削除できる」機能をピックアップして紹介します。 LWR テンプレートの機能について詳しく知りたい方は以下のドキュメントを参考にしてください。 https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/intro.htm また、LWRについてのドキュメントや サンプルソース といったリソースがまとめられたページも用意されていますので1からキャッチアップしたい方は参考になるかと思います。 https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/intro_resources.htm (個人的には サンプルアプリケーションのデプロイ と YouTubeのコンテンツ がキャッチアップに大変有用だったのでオススメです!) 2.1 SLDSデザインを削除する それでは「ヘッダーからSLDSの削除」を試してみたいと思います。 SLDSとは Salesforce Design System の略で、 Salesforce が公開しているデザインシステムです。Aura テンプレートでは標準でロードされており削除が難しかったのですが、LWR テンプレートでは コメントアウト することで完全に削除できます。 SLDSを削除することで、 デザイン面について完全にコン トロール 下におくことができます。 今回は、SLDSを削除し、代わりに CSS フレームワーク の Bulma を利用するケースを検証していきたいと思います。 サンプルソース として、公式から提供されている次のソースをLWC化して取り込んでみたいと思います。 https://bulmatemplates.github.io/bulma-templates/templates/admin.html ( サンプルソース ではBulmaの他に「Font Awesome 」「 Google Fonts」を利用していましたので以下検証でもロードしたいと思います) 1. ヘッダーを編集 Experience Cloudのビルダーページから 設定 > 詳細 > ヘッドマーク アップを編集 でヘッダーを編集します。 デフォルトで用意されているヘッダーは次の画像のようになっています。(LWRテンプレートはAuraテンプレートに比べて編集可能な箇所が多いです) 次のタグがSLDSのロード箇所になりますので、 コメントアウト します https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/brand_remove.htm < link rel = "stylesheet" href = "{ basePath }/assets/styles/salesforce-lightning-design-system.min.css?{ versionKey }" /> ちなみに < link rel = "stylesheet" href = "{ basePath }/assets/styles/dxp-site-spacing-styling-hooks.min.css?{ versionKey }" /> < link rel = "stylesheet" href = "{ basePath }/assets/styles/dxp-styling-hooks.min.css?{ versionKey }" /> < link rel = "stylesheet" href = "{ basePath }/assets/styles/dxp-slds-extensions.min.css?{ versionKey }" /> の箇所は、--dxp Styling Hooksと呼ばれる機能を反映させるための CSS になります。 https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/brand_start_using.htm --dxp Styling Hooksとは CSS カスタムプロパティを使用し、左サイドにあるテーマパネルからボタンやリンクといったHTML要素のデザインをページ全体で一括で編集できる仕組みになります。 Styling Hookは使用しない!という方は コメントアウト しても良いかと思います。(今回は一旦そのまま残しておきます) 続いて、以下 サンプルソース の <head> 内の記述から、 https://github.com/BulmaTemplates/bulma-templates/blob/master/templates/admin.html Bulma、Font Awesome 、 Google Fontsをロードするタグを追加します。 < link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" > < link rel = "stylesheet" href = "https://fonts.googleapis.com/css?family=Open+Sans:300,400,700" > < link rel = "stylesheet" href = "https://unpkg.com/bulma@0.9.0/css/bulma.min.css" /> (hrefのリンクについては Salesforce の「設定」 >「CSP 信頼済みサイト」 から登録を行います) ここまででヘッダーの記述は以下のようになっているかと思います 2. LWCを作成 ヘッダーでSLDSを削除し各ソースをロードできたので、続いてLWCを作成します。 まず、以下 サンプルソース から <body> 内の記述をそのままLWCのHTMLにコピーします。 https://github.com/BulmaTemplates/bulma-templates/blob/master/templates/admin.html 次に、以下 サンプルソース からLWCの CSS にコピーします。 https://github.com/BulmaTemplates/bulma-templates/blob/master/css/admin.css ただし、 html,body { } の箇所に関しては コンポーネント の範囲外となってしまうため、ヘッダー側に記述をしました。 3. 確認 さて、LWCがいよいよ完成したので、サイトを公開しコンテンツを確認してみたいと思います! ■ Build Your Own (LWR) ページ ■ サンプルサイト( https://bulmatemplates.github.io/bulma-templates/templates/admin.html ) いかがでしょうか? SLDSが削除されていること、Bulmaが正常にロードされていることが確認できるかと思います。 また、カード内の文章に「 Google Fonts」、検索欄に「Font Awesome 」が利用されていますが、こちらも正常に描写されていることがわかるかと思います。 ちなみに「ページ上左右のスペース」や「ボタンやリンク」のデザインが異なるかと思いますが、こちらは前述の --dxp Styling Hook が影響しており、ヘッダーから コメントアウト すると以下のようなサイトになります。 ( ピクセル パーフェクト!) 3. まとめ ここまで読んでいただきありがとうございました。 本記事がBuid Your Own (LWR) テンプレートについて理解の一助になれば幸いです。 今回、機能の紹介では「SLDSの削除」について取り上げましたが、他にも「多言語対応」「特権 スクリプト を使用した サードパーティ 製JSライブラリの利用」「LWRテンプレートのみ利用できるExperience Builderの コンポーネント 」「Salesfroce CMS との連携」等々、LWR テンプレートのユニークな機能は たくさん あります。 是非、公式ドキュメントを読んでいただき、その他の機能についてもキャッチアップしていただけると幸いです。 本記事ではLWR テンプレート利用によるWebフロントエンドの効果について主に紹介しましたが、バックエンドが Salesforce で統合されていることも大きなメリットとなります。弊社ではLWR テンプレートを利用したWebサイト開発の実績もありますので、 デザイン性が高く、高速・安全なWebサイトを フル Salesforce で実現したい方は是非ご相談ください! 執筆: @kumakura.koki.isid 、レビュー: @higa ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 インフラをIaC化している環境において、 AWS Security Hub のアラート管理方法についてのお話です。 AWS Security Hubの セキュリティ基準 を有効にすると、作成したリソースを基準に沿ってチェックし、アラートを上げてくれます。 Security Hubのセキュリティ基準は細かい設定までチェックしたりするので、数百〜数千のアラートが上がる場合があり、その対応に苦労している開発者が多いようです。アラートの数が多いと、Security Hubのコンソールから新規のアラートを探すのが難しいため、 AWS 外部へチャット通知したりチケットを起票したりする運用をよく見かけます。 さて、イン フラリ ソースをCDKなどでIaC化している場合、それに対するアラートは AWS で発生している問題ではなく、コードで発生している問題といえます。コードで発生している問題は、コード リポジトリ で管理するのが良いでしょう。 そこで「CDKでイン フラリ ソースをIaC化している」「 GitHub リポジトリ でIaCを管理している」という前提の下、Security Hub のアラートを GitHub Issues に起票する仕組みを作成してみます。 仕組みの全体像 作成手順 Security Hub とセキュリティ基準を有効にする GitHub リポジトリで Issues を有効にする GitHub Appを作成する パラメータストアに必要なパラメータを登録する CDKスタックを作成する Lambda関数を作成する 完成 さいごに 仕組みの全体像 Security Hubで検知されたアラートはEventBridgeルールで受け取ることができます。 AWS HealthやGuardDutyなど他のサービスからのアラートも送信されるため、ここで欲しいアラートをフィルタリングします。 イベントの 送信先 をLambda関数とします。パラメータストアに GitHub Appの トーク ンを生成するための 秘密鍵 などを保存しておき、 GitHub Appの トーク ンを取得して GitHub リポジトリ にIssueを作成します。Issue作成が成功したらSecurity Hubアラートのワークフローステータスを NOTIFIED に変更します。 もちろんこの仕組みを構成する AWS リソースもなるべくCDKで作成し、自分自身に対するアラートもIssue化するようにします! インフラコード本体とその問題点を同じ GitHub リポジトリ で管理できるため、問題の管理と修正を追跡しやすくなります。インフラを構築する初期段階からこの仕組みを作っておくのがおすすめで、リソースの作成・修正に伴うアラートを素早く認識でき、開発へのフィードバックが容易になるでしょう。 作成手順 Security Hub とセキュリティ基準を有効にする Security Hubとセキュリティ基準は手動で有効にします。今回は「 AWS 基礎セキュリティのベストプ ラク ティス」を利用します。 GitHub リポジトリ で Issues を有効にする IaCを管理する GitHub リポジトリ でIssues機能を有効化していない場合、有効にします。 リポジトリ のSettings > General > Features で設定できます。 GitHub Appを作成する GitHub REST API を利用するためにPersonal Access Tokenを使う方法もありますが、個人に紐づく トーク ンではなく、 Bot ユーザーとして API コールをしたいため、 GitHub App を作成します。 詳細は割愛し、ここでは概要だけ説明します。 組織アカウントを利用している場合、以下のURLから GitHub Appを新規作成する(組織のオーナー権限が必要)。作成後、App IDが画面に表示されるのでメモしておく https://github.com/organizations/ [organization名]/settings/apps 権限は Issues の Read and write を許可する。(自動的に Metadata の Read-only も許可される) GitHub App作成後の画面から 秘密鍵 を生成し、ダウンロードする 作成した GitHub Appを対象 リポジトリ にインストールする。インストール後、以下のリンクからAppを選択すると、Installation IDがURLパスに表示されるのでメモしておく https://github.com/organizations/ [organization名]/settings/installations パラメータストアに必要なパラメータを登録する AWS Systems Manager のパラメータストアに、以下のパラメータを登録します /github/GITHUB_APP_ID : GitHub Appの App ID /github/GITHUB_APP_INSTALLATION_ID : GitHub Appの Installation ID /github/GITHUB_APP_PRIVATE_KEY : ダウンロードした 秘密鍵 ファイルの中身。 SecureString として登録する CDKスタックを作成する 以下のとおりスタックを作成します。 props で AWS アカウントID、デプロイ先のリージョン、 GitHub リポジトリ のオーナー(組織)名、 リポジトリ 名をもらっています。 import { Duration , Stack , StackProps } from "aws-cdk-lib" ; import * as events from "aws-cdk-lib/aws-events" ; import * as eventTargets from "aws-cdk-lib/aws-events-targets" ; import * as iam from "aws-cdk-lib/aws-iam" ; import { Runtime } from "aws-cdk-lib/aws-lambda" ; import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs" ; import { Construct } from "constructs" ; export interface Props extends StackProps { accountId: string ; region: string ; githubOwner: string ; githubRepoName: string ; } export class GitHubIssueStack extends Stack { constructor( scope: Construct , id: string , props: Props ) { super( scope , id , props ); // Lambda関数実行ロール用のIAMポリシー // パラメータの取得と、Security Hub検出結果の更新を許可する const createGithubIssueFunctionPolicy = new iam.ManagedPolicy ( this , "CreateGithubIssueFunctionPolicy" , { managedPolicyName: "CreateGithubIssueFunctionPolicy" , statements: [ new iam.PolicyStatement ( { resources: [ `arn:aws:ssm: ${ props.region } : ${ props.accountId } :parameter/github/*` ] , actions: [ "ssm:GetParameter" ] , effect: iam.Effect.ALLOW , } ), new iam.PolicyStatement ( { resources: [ "*" ] , actions: [ "securityhub:BatchUpdateFindings" ] , effect: iam.Effect.ALLOW , } ), ] , } ); // Lambda関数 // 環境変数にGitHubリポジトリのオーナー名とリポジトリ名を渡す const createGithubIssueFunction = new lambdaNodejs.NodejsFunction ( this , "CreateGithubIssueFunction" , { entry: "functions/create-github-issue.ts" , runtime: Runtime.NODEJS_16_X , timeout: Duration.minutes ( 5 ), environment: { GITHUB_OWNER: props.githubOwner , GITHUB_REPO: props.githubRepoName , } , description: "Create GitHub Issue from EventBridge Security Hub events and update finding's workflow status" , bundling: { forceDockerBundling: false } , } ); createGithubIssueFunction.role?.addManagedPolicy ( createGithubIssueFunctionPolicy ); // EventBridgeルール。イベントパターンのフィルタリングを行う // ここではコンプライアンスステータス、製品名、レコートの状態、ワークフローステータスでフィルタリングしているが、アラートの重要度などをフィルタリング条件に追加することもできる // ワークフローステータスを NEW に限定することで、NOTIFIED に変更されたアラートを再度通知しないようにする new events.Rule ( this , "SecurityHubEventRule" , { ruleName: "security-hub-findings" , eventPattern: { source: [ "aws.securityhub" ] , detailType: [ "Security Hub Findings - Imported" ] , detail: { findings: { Compliance: { Status: [ "FAILED" ] , } , ProductName: [ "Security Hub" ] , RecordState: [ "ACTIVE" ] , Workflow: { Status: [ "NEW" ] , } , } , } , } , targets: [ new eventTargets.LambdaFunction ( createGithubIssueFunction ) ] , } ); } } Lambda関数を作成する functions/create-github-issue.ts に以下のようにLambda関数を実装します。 GitHub の トーク ンを取得するためには 秘密鍵 からJWTを生成し、 GitHub にリク エス トを投げる必要があるため、 jsonwebtoken パッケージを利用しています(TypeScriptの場合 @types/jsonwebtoken もインストール)。リク エス トには axios パッケージを利用しています。 また、 GitHub のIssue作成は Octokit( @octokit/rest パッケージ)からリク エス トを投げています。 import { SecurityHubClient , BatchUpdateFindingsCommand , BatchUpdateFindingsCommandInput , WorkflowStatus , } from "@aws-sdk/client-securityhub" ; import { SSMClient , GetParameterCommand } from "@aws-sdk/client-ssm" ; import { Octokit } from "@octokit/rest" ; import { Handler , EventBridgeEvent } from "aws-lambda" ; import axios from "axios" ; import { sign } from "jsonwebtoken" ; export const handler: Handler = async ( event: EventBridgeEvent < string , Detail >) => { // GitHubのAccess Tokenを取得する関数 const token = await getGitHubToken (); const octokit = new Octokit ( { auth: token } ); await Promise . all( event.detail.findings.map (async ( finding ) => { try { // 作成するIssueのボディテキスト const body = `## ${ finding.Title } * Security Hub コントロールID: \` ${ finding.ProductFields.ControlId ?? finding.Compliance.SecurityControlId ?? "" } \` * 重要度: \` ${ finding.Severity.Label } \` * 説明: ${ finding.Description } * リージョン: \` ${ finding.Region } \` * リソースID: ${ finding.ProductFields[ "Resources:0/Id" ] } * 対応方法: ${ finding.ProductFields.RecommendationUrl ?? finding.Remediation.Recommendation.Url } * 最初の観測日時: ${ finding.FirstObservedAt } * ID: \` ${ finding.Id } \`` ; // Issueを作成 const res = await octokit.request ( `POST /repos/ ${process .env.GITHUB_OWNER } / ${process .env.GITHUB_REPO } /issues` , { owner: process .env.GITHUB_OWNER , repo: process .env.GITHUB_REPO , title: finding.Title , body: body , labels: [ "Security Hub" ] , } ); if ( res. status === 201 ) { console .log ( `Issue created. [ID] ${ finding.Id } ` ); // Issueの作成が成功したら、検出結果のワークフローステータスを変更する await setFindingNotified ( finding.Id , finding.ProductArn ); } else { console .error ( `Issue creation failed. [ID] ${ finding.Id } [Status] ${ res. status } ` ); } } catch ( e ) { console .error ( `Issue creation failed. [ID] ${ finding.Id } [Message] ${ e instanceof Error ? e.message : "" } ` ); } } ) ); } ; イベントの型は以下のとおり定義しています。ほぼ全フィールドを網羅していますが、使用するフィールドのみを定義しても良いでしょう。 (2023/2/28追記)Security Hubの 検出結果の集約 機能が利用可能になり、 一部のフィールドが削除 される場合があります。これに合わせてフィールド定義を修正しました。 type Detail = { findings: Finding [] ; } ; type Finding = { SchemaVersion: string ; Id: string ; ProductArn: string ; GeneratorId: string ; AwsAccountId: string ; Types: string [] ; FirstObservedAt: string ; LastObservedAt: string ; CreatedAt: string ; UpdatedAt: string ; Severity: { Normalized: number ; Label: string ; Product?: number ; Original: string } ; Title: string ; Description: string ; Remediation: { Recommendation: { Text : string ; Url: string } } ; ProductFields: { StandardsArn?: string ; StandardsSubscriptionArn?: string ; ControlId?: string ; RecommendationUrl?: string ; "RelatedAWSResources:0/name" : string ; "RelatedAWSResources:0/type" : string ; StandardsControlArn?: string ; "aws/securityhub/ProductName" : string ; "aws/securityhub/CompanyName" : string ; "Resources:0/Id" : string ; "aws/securityhub/FindingId" : string ; } ; Resources: { Type: string ; Id: string ; Partition: string ; Region: string ; Details: any }[] ; RecordState: string ; WorkflowState: string ; Workflow: { Status: string } ; Compliance: { Status: string ; SecurityControlId?: string } ; ProductName: string ; CompanyName: string ; FindingProviderFields: { Types: string [] ; Severity: { Normalized: number ; Label: string ; Product: number ; Original: string } ; } ; Region: string ; } ; GitHub から トーク ンを取得する関数は次のとおりです。 async function getGitHubToken () : Promise < string > { // App IDを取得 const appId = await getParameter ( "/github/GITHUB_APP_ID" , false ); const payload = { iat: Math .floor ( Date .now () / 1000 ) - 10 , exp: Math .floor ( Date .now () / 1000 ) + 60 , iss: appId , } ; // 秘密鍵を取得 const privateKey = await getParameter ( "/github/GITHUB_APP_PRIVATE_KEY" , true ); // 秘密鍵を含んだJWTを生成 const token = sign ( payload , privateKey , { algorithm: "RS256" } ); // Installation Idを取得 const installationId = await getParameter ( "/github/GITHUB_APP_INSTALLATION_ID" , false ); // GitHub Access Tokenをリクエスト const res = await axios.post < { token?: string } >( `https://api.github.com/app/installations/ ${ installationId } /access_tokens` , null , { headers: { Authorization: "Bearer " + token , Accept: "application/vnd.github+json" , } , } ); if ( res.data.token ) { return res.data.token ; } else { throw new Error ( "Failed to get access token" ); } } const ssmClient = new SSMClient ( { region: process .env.AWS_REGION } ); // パラメータストアからパラメータを取得する関数 async function getParameter ( name: string , encrypted: boolean ) : Promise < string > { const input = { Name: name , WithDecryption: encrypted , } ; const command = new GetParameterCommand ( input ); const ssmRes = await ssmClient.send ( command ); const param = ssmRes.Parameter?.Value ; if ( ! param ) { throw new Error ( `Failed to get ${ name } from SSM parameter store` ); } return param ; } Issueを作成したアラートのワークフローステータスを NOTIFIED に変更する関数です。 const securityHubClient = new SecurityHubClient ( { region: process .env.AWS_REGION } ); async function setFindingNotified ( findingId: string , productArn: string ) { const params: BatchUpdateFindingsCommandInput = { FindingIdentifiers: [{ Id: findingId , ProductArn: productArn }] , Workflow: { Status: WorkflowStatus.NOTIFIED } , } ; const command = new BatchUpdateFindingsCommand ( params ); await securityHubClient.send ( command ); } 完成 以上で完成です。スタックをデプロイしてみると、早速このスタックに対して CloudFormation.1 という Issue が作成されました。便利な修復方法のリンクもイベント内容に含まれているので、Issue内容に追加しています。 あとは開発チームの問題管理フローで対応していけば良いですね。 さいごに ここまで紹介した仕組みではIssueの作成までを自動化し、Issueのクローズは手動でする必要があります。 作成されたIssue IDと検出結果IDの関連を DynamoDBテーブルなどに保管すれば、リソースの修正によって解決したIssueを自動でクローズする仕組みも作ることができそうです。 IaCで作成したリソースの問題点を見逃さずに適切に管理し、セキュアなインフラを作成していきましょう! 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 - セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo2 、レビュー: @higa ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 インフラをIaC化している環境において、 AWS Security Hub のアラート管理方法についてのお話です。 AWS Security Hubの セキュリティ基準 を有効にすると、作成したリソースを基準に沿ってチェックし、アラートを上げてくれます。 Security Hubのセキュリティ基準は細かい設定までチェックしたりするので、数百〜数千のアラートが上がる場合があり、その対応に苦労している開発者が多いようです。アラートの数が多いと、Security Hubのコンソールから新規のアラートを探すのが難しいため、 AWS 外部へチャット通知したりチケットを起票したりする運用をよく見かけます。 さて、イン フラリ ソースをCDKなどでIaC化している場合、それに対するアラートは AWS で発生している問題ではなく、コードで発生している問題といえます。コードで発生している問題は、コード リポジトリ で管理するのが良いでしょう。 そこで「CDKでイン フラリ ソースをIaC化している」「 GitHub リポジトリ でIaCを管理している」という前提の下、Security Hub のアラートを GitHub Issues に起票する仕組みを作成してみます。 仕組みの全体像 作成手順 Security Hub とセキュリティ基準を有効にする GitHub リポジトリで Issues を有効にする GitHub Appを作成する パラメータストアに必要なパラメータを登録する CDKスタックを作成する Lambda関数を作成する 完成 さいごに 仕組みの全体像 Security Hubで検知されたアラートはEventBridgeルールで受け取ることができます。 AWS HealthやGuardDutyなど他のサービスからのアラートも送信されるため、ここで欲しいアラートをフィルタリングします。 イベントの 送信先 をLambda関数とします。パラメータストアに GitHub Appの トーク ンを生成するための 秘密鍵 などを保存しておき、 GitHub Appの トーク ンを取得して GitHub リポジトリ にIssueを作成します。Issue作成が成功したらSecurity Hubアラートのワークフローステータスを NOTIFIED に変更します。 もちろんこの仕組みを構成する AWS リソースもなるべくCDKで作成し、自分自身に対するアラートもIssue化するようにします! インフラコード本体とその問題点を同じ GitHub リポジトリ で管理できるため、問題の管理と修正を追跡しやすくなります。インフラを構築する初期段階からこの仕組みを作っておくのがおすすめで、リソースの作成・修正に伴うアラートを素早く認識でき、開発へのフィードバックが容易になるでしょう。 作成手順 Security Hub とセキュリティ基準を有効にする Security Hubとセキュリティ基準は手動で有効にします。今回は「 AWS 基礎セキュリティのベストプ ラク ティス」を利用します。 GitHub リポジトリ で Issues を有効にする IaCを管理する GitHub リポジトリ でIssues機能を有効化していない場合、有効にします。 リポジトリ のSettings > General > Features で設定できます。 GitHub Appを作成する GitHub REST API を利用するためにPersonal Access Tokenを使う方法もありますが、個人に紐づく トーク ンではなく、 Bot ユーザーとして API コールをしたいため、 GitHub App を作成します。 詳細は割愛し、ここでは概要だけ説明します。 組織アカウントを利用している場合、以下のURLから GitHub Appを新規作成する(組織のオーナー権限が必要)。作成後、App IDが画面に表示されるのでメモしておく https://github.com/organizations/ [organization名]/settings/apps 権限は Issues の Read and write を許可する。(自動的に Metadata の Read-only も許可される) GitHub App作成後の画面から 秘密鍵 を生成し、ダウンロードする 作成した GitHub Appを対象 リポジトリ にインストールする。インストール後、以下のリンクからAppを選択すると、Installation IDがURLパスに表示されるのでメモしておく https://github.com/organizations/ [organization名]/settings/installations パラメータストアに必要なパラメータを登録する AWS Systems Manager のパラメータストアに、以下のパラメータを登録します /github/GITHUB_APP_ID : GitHub Appの App ID /github/GITHUB_APP_INSTALLATION_ID : GitHub Appの Installation ID /github/GITHUB_APP_PRIVATE_KEY : ダウンロードした 秘密鍵 ファイルの中身。 SecureString として登録する CDKスタックを作成する 以下のとおりスタックを作成します。 props で AWS アカウントID、デプロイ先のリージョン、 GitHub リポジトリ のオーナー(組織)名、 リポジトリ 名をもらっています。 import { Duration , Stack , StackProps } from "aws-cdk-lib" ; import * as events from "aws-cdk-lib/aws-events" ; import * as eventTargets from "aws-cdk-lib/aws-events-targets" ; import * as iam from "aws-cdk-lib/aws-iam" ; import { Runtime } from "aws-cdk-lib/aws-lambda" ; import * as lambdaNodejs from "aws-cdk-lib/aws-lambda-nodejs" ; import { Construct } from "constructs" ; export interface Props extends StackProps { accountId: string ; region: string ; githubOwner: string ; githubRepoName: string ; } export class GitHubIssueStack extends Stack { constructor( scope: Construct , id: string , props: Props ) { super( scope , id , props ); // Lambda関数実行ロール用のIAMポリシー // パラメータの取得と、Security Hub検出結果の更新を許可する const createGithubIssueFunctionPolicy = new iam.ManagedPolicy ( this , "CreateGithubIssueFunctionPolicy" , { managedPolicyName: "CreateGithubIssueFunctionPolicy" , statements: [ new iam.PolicyStatement ( { resources: [ `arn:aws:ssm: ${ props.region } : ${ props.accountId } :parameter/github/*` ] , actions: [ "ssm:GetParameter" ] , effect: iam.Effect.ALLOW , } ), new iam.PolicyStatement ( { resources: [ "*" ] , actions: [ "securityhub:BatchUpdateFindings" ] , effect: iam.Effect.ALLOW , } ), ] , } ); // Lambda関数 // 環境変数にGitHubリポジトリのオーナー名とリポジトリ名を渡す const createGithubIssueFunction = new lambdaNodejs.NodejsFunction ( this , "CreateGithubIssueFunction" , { entry: "functions/create-github-issue.ts" , runtime: Runtime.NODEJS_16_X , timeout: Duration.minutes ( 5 ), environment: { GITHUB_OWNER: props.githubOwner , GITHUB_REPO: props.githubRepoName , } , description: "Create GitHub Issue from EventBridge Security Hub events and update finding's workflow status" , bundling: { forceDockerBundling: false } , } ); createGithubIssueFunction.role?.addManagedPolicy ( createGithubIssueFunctionPolicy ); // EventBridgeルール。イベントパターンのフィルタリングを行う // ここではコンプライアンスステータス、製品名、レコートの状態、ワークフローステータスでフィルタリングしているが、アラートの重要度などをフィルタリング条件に追加することもできる // ワークフローステータスを NEW に限定することで、NOTIFIED に変更されたアラートを再度通知しないようにする new events.Rule ( this , "SecurityHubEventRule" , { ruleName: "security-hub-findings" , eventPattern: { source: [ "aws.securityhub" ] , detailType: [ "Security Hub Findings - Imported" ] , detail: { findings: { Compliance: { Status: [ "FAILED" ] , } , ProductName: [ "Security Hub" ] , RecordState: [ "ACTIVE" ] , Workflow: { Status: [ "NEW" ] , } , } , } , } , targets: [ new eventTargets.LambdaFunction ( createGithubIssueFunction ) ] , } ); } } Lambda関数を作成する functions/create-github-issue.ts に以下のようにLambda関数を実装します。 GitHub の トーク ンを取得するためには 秘密鍵 からJWTを生成し、 GitHub にリク エス トを投げる必要があるため、 jsonwebtoken パッケージを利用しています(TypeScriptの場合 @types/jsonwebtoken もインストール)。リク エス トには axios パッケージを利用しています。 また、 GitHub のIssue作成は Octokit( @octokit/rest パッケージ)からリク エス トを投げています。 import { SecurityHubClient , BatchUpdateFindingsCommand , BatchUpdateFindingsCommandInput , WorkflowStatus , } from "@aws-sdk/client-securityhub" ; import { SSMClient , GetParameterCommand } from "@aws-sdk/client-ssm" ; import { Octokit } from "@octokit/rest" ; import { Handler , EventBridgeEvent } from "aws-lambda" ; import axios from "axios" ; import { sign } from "jsonwebtoken" ; export const handler: Handler = async ( event: EventBridgeEvent < string , Detail >) => { // GitHubのAccess Tokenを取得する関数 const token = await getGitHubToken (); const octokit = new Octokit ( { auth: token } ); await Promise . all( event.detail.findings.map (async ( finding ) => { try { // 作成するIssueのボディテキスト const body = `## ${ finding.Title } * Security Hub コントロールID: \` ${ finding.ProductFields.ControlId ?? finding.Compliance.SecurityControlId ?? "" } \` * 重要度: \` ${ finding.Severity.Label } \` * 説明: ${ finding.Description } * リージョン: \` ${ finding.Region } \` * リソースID: ${ finding.ProductFields[ "Resources:0/Id" ] } * 対応方法: ${ finding.ProductFields.RecommendationUrl ?? finding.Remediation.Recommendation.Url } * 最初の観測日時: ${ finding.FirstObservedAt } * ID: \` ${ finding.Id } \`` ; // Issueを作成 const res = await octokit.request ( `POST /repos/ ${process .env.GITHUB_OWNER } / ${process .env.GITHUB_REPO } /issues` , { owner: process .env.GITHUB_OWNER , repo: process .env.GITHUB_REPO , title: finding.Title , body: body , labels: [ "Security Hub" ] , } ); if ( res. status === 201 ) { console .log ( `Issue created. [ID] ${ finding.Id } ` ); // Issueの作成が成功したら、検出結果のワークフローステータスを変更する await setFindingNotified ( finding.Id , finding.ProductArn ); } else { console .error ( `Issue creation failed. [ID] ${ finding.Id } [Status] ${ res. status } ` ); } } catch ( e ) { console .error ( `Issue creation failed. [ID] ${ finding.Id } [Message] ${ e instanceof Error ? e.message : "" } ` ); } } ) ); } ; イベントの型は以下のとおり定義しています。ほぼ全フィールドを網羅していますが、使用するフィールドのみを定義しても良いでしょう。 (2023/2/28追記)Security Hubの 検出結果の集約 機能が利用可能になり、 一部のフィールドが削除 される場合があります。これに合わせてフィールド定義を修正しました。 type Detail = { findings: Finding [] ; } ; type Finding = { SchemaVersion: string ; Id: string ; ProductArn: string ; GeneratorId: string ; AwsAccountId: string ; Types: string [] ; FirstObservedAt: string ; LastObservedAt: string ; CreatedAt: string ; UpdatedAt: string ; Severity: { Normalized: number ; Label: string ; Product?: number ; Original: string } ; Title: string ; Description: string ; Remediation: { Recommendation: { Text : string ; Url: string } } ; ProductFields: { StandardsArn?: string ; StandardsSubscriptionArn?: string ; ControlId?: string ; RecommendationUrl?: string ; "RelatedAWSResources:0/name" : string ; "RelatedAWSResources:0/type" : string ; StandardsControlArn?: string ; "aws/securityhub/ProductName" : string ; "aws/securityhub/CompanyName" : string ; "Resources:0/Id" : string ; "aws/securityhub/FindingId" : string ; } ; Resources: { Type: string ; Id: string ; Partition: string ; Region: string ; Details: any }[] ; RecordState: string ; WorkflowState: string ; Workflow: { Status: string } ; Compliance: { Status: string ; SecurityControlId?: string } ; ProductName: string ; CompanyName: string ; FindingProviderFields: { Types: string [] ; Severity: { Normalized: number ; Label: string ; Product: number ; Original: string } ; } ; Region: string ; } ; GitHub から トーク ンを取得する関数は次のとおりです。 async function getGitHubToken () : Promise < string > { // App IDを取得 const appId = await getParameter ( "/github/GITHUB_APP_ID" , false ); const payload = { iat: Math .floor ( Date .now () / 1000 ) - 10 , exp: Math .floor ( Date .now () / 1000 ) + 60 , iss: appId , } ; // 秘密鍵を取得 const privateKey = await getParameter ( "/github/GITHUB_APP_PRIVATE_KEY" , true ); // 秘密鍵を含んだJWTを生成 const token = sign ( payload , privateKey , { algorithm: "RS256" } ); // Installation Idを取得 const installationId = await getParameter ( "/github/GITHUB_APP_INSTALLATION_ID" , false ); // GitHub Access Tokenをリクエスト const res = await axios.post < { token?: string } >( `https://api.github.com/app/installations/ ${ installationId } /access_tokens` , null , { headers: { Authorization: "Bearer " + token , Accept: "application/vnd.github+json" , } , } ); if ( res.data.token ) { return res.data.token ; } else { throw new Error ( "Failed to get access token" ); } } const ssmClient = new SSMClient ( { region: process .env.AWS_REGION } ); // パラメータストアからパラメータを取得する関数 async function getParameter ( name: string , encrypted: boolean ) : Promise < string > { const input = { Name: name , WithDecryption: encrypted , } ; const command = new GetParameterCommand ( input ); const ssmRes = await ssmClient.send ( command ); const param = ssmRes.Parameter?.Value ; if ( ! param ) { throw new Error ( `Failed to get ${ name } from SSM parameter store` ); } return param ; } Issueを作成したアラートのワークフローステータスを NOTIFIED に変更する関数です。 const securityHubClient = new SecurityHubClient ( { region: process .env.AWS_REGION } ); async function setFindingNotified ( findingId: string , productArn: string ) { const params: BatchUpdateFindingsCommandInput = { FindingIdentifiers: [{ Id: findingId , ProductArn: productArn }] , Workflow: { Status: WorkflowStatus.NOTIFIED } , } ; const command = new BatchUpdateFindingsCommand ( params ); await securityHubClient.send ( command ); } 完成 以上で完成です。スタックをデプロイしてみると、早速このスタックに対して CloudFormation.1 という Issue が作成されました。便利な修復方法のリンクもイベント内容に含まれているので、Issue内容に追加しています。 あとは開発チームの問題管理フローで対応していけば良いですね。 さいごに ここまで紹介した仕組みではIssueの作成までを自動化し、Issueのクローズは手動でする必要があります。 作成されたIssue IDと検出結果IDの関連を DynamoDBテーブルなどに保管すれば、リソースの修正によって解決したIssueを自動でクローズする仕組みも作ることができそうです。 IaCで作成したリソースの問題点を見逃さずに適切に管理し、セキュアなインフラを作成していきましょう! 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 - セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo2 、レビュー: @higa ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、魅惑的な女アニメ画(トゥーン レンダリング )の呪文です。 アニメ画と言っても 美少女アニメ画編 でとりあげたような、animeキーワードを用いるものではなく、トゥーン レンダリング を使ったアニメ画になります。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 トゥーンレンダリング cel shaded art of a seductive girl, beautiful face, cute eyes black and white cel shaded art artstation, deviantart, concept art, digital painting, award-winning seductive beautiful girl, upper shot, seductive posing, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing princess posing まとめ 仲間募集 Stable Diffusionの過去コンテンツ トゥーン レンダリング トゥーン レンダリング とは、コンピュータグラフィックスにおいて3Dモデルを手描きアニメーション、あるいは漫画やイラスト風の作画(アニメ絵)で レンダリング する手法のことです。 wikipedia トゥーンレンダリング ゼルダの伝説 ブレス オブ ザ ワイルド のTrailerを見ると、どういうものかわかるでしょう。 Stable Diffusionでは、画像タイプとして、cel shaded artを使います。 cel shaded art of a seductive girl, beautiful face, cute eyes seductive(魅惑的な)が、今回の記事の最も重要なキーワードです。seductiveをつけた サブジ ェクト(描画対象)は文字通り魅惑的になりますが、NSFW(職場での閲覧は危険)になりやすいという欠点も持っています。 人物を描画する場合、faceとeyesのキワードは必ず入れておきましょう。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive girl, beautiful face, cute eyes 出力された画像はこちら。 black and white cel shaded art cel shaded artは、black and whiteのキーワードを付けると、別の魅力が発揮されます。今回の記事では、black and whiteのありなしの2つのパターンを紹介します。 今回のPrompt(呪文)はこちら。 black and white cel shaded art of a seductive girl, beautiful face, cute eyes 出力された画像はこちら。 今回は、最初から、クオリティが高いですね。さすが、seductive(魅惑的)。 artstation, deviantart , concept art, digital painting, award-winning これまでの入門シリーズをやってきた方なら、次に追加する呪文は、わかっていますね。そうです。作風の呪文です。 日本人以外を描画する場合は、artstation, deviantart を指定します。日本人を描画する場合は、pixiv, light novelを指定します。 concept art, digital painting, award-winningは、お決まりの呪文なので、セットで覚えてしまいましょう。この呪文により、クオリティが多少上がります。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive girl, beautiful face, cute eyes, artstation, deviantart, concept art, digital painting, award-winning 出力された画像はこちら。 白黒バージョンはこちら。 seductive beautiful girl, upper shot, seductive posing, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing いよいよ仕上げです。クオリティの高い人物画像を出力するには、服装(costume)、背景(background)、構図(composition)、ライティング(lighting)をしっかり指定することが重要です。 cinematic postprocessingは、出力される画像を映画の1シーンのようにかっこよくしてくれます。 upper shot, seductive posingで、魅力的なポーズの上半身を撮します。posingがあったほうが、より画像が生き生きします。 seductiveとposingが一緒に組み合わされると、あまりにも頻繁にNSFW(職場での閲覧は危険)が起きるので、seductive girlをseductive beautiful girlに変更しました。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive beautiful girl, beautiful face, cute eyes, upper shot, seductive posing, artstation, deviantart, concept art, digital painting, award-winning, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing 出力された画像はこちら。 白黒バージョンはこちら。 princess posing seductive(魅惑的な) posingの他におすすめなのが、princess(王女) posingです。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive beautiful girl, beautiful face, cute eyes, upper shot, princess posing, artstation, deviantart, concept art, digital painting, award-winning, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing 出力された画像はこちら。 白黒バージョンはこちら。 まとめ 今回は、魅惑的な女アニメ画(トゥーン レンダリング )を扱いました。seductive(魅惑的な)の呪文は、NSFW(職場での閲覧は危険)が出やすい難しい呪文ですが、beautifulと組み合わせることで、扱いやすくなることを説明しました。 posingも画像を生き生きさせる効果があります。 次回は、 美少女を高確率で出す呪文編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、魅惑的な女アニメ画(トゥーン レンダリング )の呪文です。 アニメ画と言っても 美少女アニメ画編 でとりあげたような、animeキーワードを用いるものではなく、トゥーン レンダリング を使ったアニメ画になります。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 トゥーンレンダリング cel shaded art of a seductive girl, beautiful face, cute eyes black and white cel shaded art artstation, deviantart, concept art, digital painting, award-winning seductive beautiful girl, upper shot, seductive posing, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing princess posing まとめ 仲間募集 Stable Diffusionの過去コンテンツ トゥーン レンダリング トゥーン レンダリング とは、コンピュータグラフィックスにおいて3Dモデルを手描きアニメーション、あるいは漫画やイラスト風の作画(アニメ絵)で レンダリング する手法のことです。 wikipedia トゥーンレンダリング ゼルダの伝説 ブレス オブ ザ ワイルド のTrailerを見ると、どういうものかわかるでしょう。 Stable Diffusionでは、画像タイプとして、cel shaded artを使います。 cel shaded art of a seductive girl, beautiful face, cute eyes seductive(魅惑的な)が、今回の記事の最も重要なキーワードです。seductiveをつけた サブジ ェクト(描画対象)は文字通り魅惑的になりますが、NSFW(職場での閲覧は危険)になりやすいという欠点も持っています。 人物を描画する場合、faceとeyesのキワードは必ず入れておきましょう。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive girl, beautiful face, cute eyes 出力された画像はこちら。 black and white cel shaded art cel shaded artは、black and whiteのキーワードを付けると、別の魅力が発揮されます。今回の記事では、black and whiteのありなしの2つのパターンを紹介します。 今回のPrompt(呪文)はこちら。 black and white cel shaded art of a seductive girl, beautiful face, cute eyes 出力された画像はこちら。 今回は、最初から、クオリティが高いですね。さすが、seductive(魅惑的)。 artstation, deviantart , concept art, digital painting, award-winning これまでの入門シリーズをやってきた方なら、次に追加する呪文は、わかっていますね。そうです。作風の呪文です。 日本人以外を描画する場合は、artstation, deviantart を指定します。日本人を描画する場合は、pixiv, light novelを指定します。 concept art, digital painting, award-winningは、お決まりの呪文なので、セットで覚えてしまいましょう。この呪文により、クオリティが多少上がります。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive girl, beautiful face, cute eyes, artstation, deviantart, concept art, digital painting, award-winning 出力された画像はこちら。 白黒バージョンはこちら。 seductive beautiful girl, upper shot, seductive posing, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing いよいよ仕上げです。クオリティの高い人物画像を出力するには、服装(costume)、背景(background)、構図(composition)、ライティング(lighting)をしっかり指定することが重要です。 cinematic postprocessingは、出力される画像を映画の1シーンのようにかっこよくしてくれます。 upper shot, seductive posingで、魅力的なポーズの上半身を撮します。posingがあったほうが、より画像が生き生きします。 seductiveとposingが一緒に組み合わされると、あまりにも頻繁にNSFW(職場での閲覧は危険)が起きるので、seductive girlをseductive beautiful girlに変更しました。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive beautiful girl, beautiful face, cute eyes, upper shot, seductive posing, artstation, deviantart, concept art, digital painting, award-winning, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing 出力された画像はこちら。 白黒バージョンはこちら。 princess posing seductive(魅惑的な) posingの他におすすめなのが、princess(王女) posingです。 今回のPrompt(呪文)はこちら。 cel shaded art of a seductive beautiful girl, beautiful face, cute eyes, upper shot, princess posing, artstation, deviantart, concept art, digital painting, award-winning, beautiful costume, fantasy background, beautiful composition, cinematic lighting, cinematic postprocessing 出力された画像はこちら。 白黒バージョンはこちら。 まとめ 今回は、魅惑的な女アニメ画(トゥーン レンダリング )を扱いました。seductive(魅惑的な)の呪文は、NSFW(職場での閲覧は危険)が出やすい難しい呪文ですが、beautifulと組み合わせることで、扱いやすくなることを説明しました。 posingも画像を生き生きさせる効果があります。 次回は、 美少女を高確率で出す呪文編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
初めに ISID X(クロス) イノベーション 本部 の三浦です。 筆者の関わってる案件では、セキュリ ティー の強化の一環として、 AWS session manager利用を推進しております。 session managerを利用するとEC2アクセス時に下記のようなメリットがあります(※1)。 ssh ,rdp接続のためのpublic ipを付与する必要がなくなる プライベートなサブネットのec2にも、踏み台等を経由せずにアクセス可能 ssh ,rdp接続のためのSGインバウンド許可IP制御が不要となる 認証情報を AWS の権限に集約でき、window、 linux のユーザー管理を減らせる 接続ログ、監査ログを、session mangerで一元管理できる しかし、そこで問題になってくるのがセキュリ ティー 強化のためにsession manger用のアクセスキー、シークレットキーを 配布すると今度はその管理が煩雑となり、セキュリ ティー リスクとなる課題があります。 そこで、 AWS Tools for Windows PowerShell からIdP(adfs)接続用のコマンドレット(Set-AWSSamlRoleProfile)を使い(※2)アクセスキー、シークレットキーの配布なしにsession mangerを利用する方法を記述します。 が、現在の仕様では、 PowerShell からsession managerの開始の API を単純に呼び出しても動作しません(※3)。 しかし、一工夫することにより、アクセスキー、シークレットキーなしでセキュアにsession mangerの利用が可能となります 実装の概要 AWS Tools for Windows PowerShell で、IdP(ADFS)より AWS のアクセス権取得 STS トーク ンを取り、 AWS CLI が使える形式で保存 AWS CLI からsession manger実行 これだけとなります。adfsへのアクセスのところのみ PowerShell をもちい、 AWS CLI でsession mangerを呼び出すだけとなります。 ソースコード 例 Import-Module -Name AWS.Tools.Common Import-Module -Name AWS.Tools.SecurityToken function start-ssm { [CmdletBinding()] Param ( [string] $awsAccountId = $null , [string] $adfsRoleName = "ADFS-RoleName" , [string] $ec2InstanceId = $null , [string] $localPortNumber = "13389" ) $profileName = $awsAccountId + ":role/" + $adfsRoleName $roleArn = "arn:aws:iam::" + $awsAccountId + ":role/" + $adfsRoleName ### XXXXXXXXXXXの部分は適宜、お使いのADFSのドメインに置き換えてください。筆者はadfs v3で動作確認をしております $endpoint = "https://XXXXXXXXXXX/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices" $epName = Set-AWSSamlEndpoint -Endpoint $endpoint -StoreAs ADFS-Demo -AuthenticationType NTLM $r = Set-AWSSamlRoleProfile -EndpointName $epName -StoreAllRoles $Creds = ( Use-STSRole -Region ap-northeast-1 -ProfileName $profileName -RoleArn $roleArn -RoleSessionName $adfsRoleName ).Credentials ### 動作をわかりやすくするために、下記三行でSTSの内容をコンソール出力しています $Creds .AccessKeyId $Creds .SecretAccessKey $Creds .SessionToken aws configure set region ap-northeast-1 --profile adfstemp aws configure set aws_access_key_id $Creds .AccessKeyId --profile adfstemp aws configure set aws_secret_access_key $Creds .SecretAccessKey --profile adfstemp aws configure set aws_session_token $Creds .SessionToken --profile adfstemp ## 下記はRDPのポートフォワーディング用の例となります $ssmParam = "portNumber=3389, localPortNumber=" + $localPortNumber aws ssm start-session --target $ec2InstanceId -- document-name AWS-StartPortForwardingSession --parameters $ssmParam --profile adfstemp } Set-AWSSamlEndpoint、 Set-AWSSamlRoleProfileを用いて、IdP(ADFS)より AWS のアクセス権取得 Use-STSRoleを用いて AWS CLI 用の認証情報を取得し、 aws configureで保存 AWS CLI の aws ssm start-sessionで、session mangerを開始 としてしてるだけの、非常にシンプルなコードとなります。 最後に ということで、今回は、アクセスキー、シークレットキーを発行せずに、session mangerを利用する例をご紹介いたしました。筆者は、200アカウントぐらいの管理をしており、これを個別のiam userのアクセスキー、シークレットキーで管理しようとすると非常につらいものがあります。 そのため、認証情報を、IdPサーバーに寄せた運用をしております。 アクセスキー管理に悩まれてる方は、ぜひ、一度、IdPサーバから STS を取得する運用を試されてはいかがでしょうか? (※1) session mangerの概要、様々な使い方については、クラスメソッド様のブログに 多数記事 がございますので、session mangerってなんだっけ?という方は、そちらを見ていただくのがおすすめです。 (※2) AWS Tools for Windows PowerShell を用いると、標準ツールのみで 非常に簡単にadfsから認証情報の取得が可能 です。 (※3) 「 PowerShell からsession managerの開始ができない件」については、クラスメソッドさんが詳細を書かれていますので、詳細が気になる方はこちらをご参照ください。 PowerShellでSSMのポートフォワーディングを試してみた(けど駄目だったはなし) 執筆: @miura.toshihiko 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
初めに ISID X(クロス) イノベーション 本部 の三浦です。 筆者の関わってる案件では、セキュリ ティー の強化の一環として、 AWS session manager利用を推進しております。 session managerを利用するとEC2アクセス時に下記のようなメリットがあります(※1)。 ssh ,rdp接続のためのpublic ipを付与する必要がなくなる プライベートなサブネットのec2にも、踏み台等を経由せずにアクセス可能 ssh ,rdp接続のためのSGインバウンド許可IP制御が不要となる 認証情報を AWS の権限に集約でき、window、 linux のユーザー管理を減らせる 接続ログ、監査ログを、session mangerで一元管理できる しかし、そこで問題になってくるのがセキュリ ティー 強化のためにsession manger用のアクセスキー、シークレットキーを 配布すると今度はその管理が煩雑となり、セキュリ ティー リスクとなる課題があります。 そこで、 AWS Tools for Windows PowerShell からIdP(adfs)接続用のコマンドレット(Set-AWSSamlRoleProfile)を使い(※2)アクセスキー、シークレットキーの配布なしにsession mangerを利用する方法を記述します。 が、現在の仕様では、 PowerShell からsession managerの開始の API を単純に呼び出しても動作しません(※3)。 しかし、一工夫することにより、アクセスキー、シークレットキーなしでセキュアにsession mangerの利用が可能となります 実装の概要 AWS Tools for Windows PowerShell で、IdP(ADFS)より AWS のアクセス権取得 STS トーク ンを取り、 AWS CLI が使える形式で保存 AWS CLI からsession manger実行 これだけとなります。adfsへのアクセスのところのみ PowerShell をもちい、 AWS CLI でsession mangerを呼び出すだけとなります。 ソースコード 例 Import-Module -Name AWS.Tools.Common Import-Module -Name AWS.Tools.SecurityToken function start-ssm { [CmdletBinding()] Param ( [string] $awsAccountId = $null , [string] $adfsRoleName = "ADFS-RoleName" , [string] $ec2InstanceId = $null , [string] $localPortNumber = "13389" ) $profileName = $awsAccountId + ":role/" + $adfsRoleName $roleArn = "arn:aws:iam::" + $awsAccountId + ":role/" + $adfsRoleName ### XXXXXXXXXXXの部分は適宜、お使いのADFSのドメインに置き換えてください。筆者はadfs v3で動作確認をしております $endpoint = "https://XXXXXXXXXXX/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices" $epName = Set-AWSSamlEndpoint -Endpoint $endpoint -StoreAs ADFS-Demo -AuthenticationType NTLM $r = Set-AWSSamlRoleProfile -EndpointName $epName -StoreAllRoles $Creds = ( Use-STSRole -Region ap-northeast-1 -ProfileName $profileName -RoleArn $roleArn -RoleSessionName $adfsRoleName ).Credentials ### 動作をわかりやすくするために、下記三行でSTSの内容をコンソール出力しています $Creds .AccessKeyId $Creds .SecretAccessKey $Creds .SessionToken aws configure set region ap-northeast-1 --profile adfstemp aws configure set aws_access_key_id $Creds .AccessKeyId --profile adfstemp aws configure set aws_secret_access_key $Creds .SecretAccessKey --profile adfstemp aws configure set aws_session_token $Creds .SessionToken --profile adfstemp ## 下記はRDPのポートフォワーディング用の例となります $ssmParam = "portNumber=3389, localPortNumber=" + $localPortNumber aws ssm start-session --target $ec2InstanceId -- document-name AWS-StartPortForwardingSession --parameters $ssmParam --profile adfstemp } Set-AWSSamlEndpoint、 Set-AWSSamlRoleProfileを用いて、IdP(ADFS)より AWS のアクセス権取得 Use-STSRoleを用いて AWS CLI 用の認証情報を取得し、 aws configureで保存 AWS CLI の aws ssm start-sessionで、session mangerを開始 としてしてるだけの、非常にシンプルなコードとなります。 最後に ということで、今回は、アクセスキー、シークレットキーを発行せずに、session mangerを利用する例をご紹介いたしました。筆者は、200アカウントぐらいの管理をしており、これを個別のiam userのアクセスキー、シークレットキーで管理しようとすると非常につらいものがあります。 そのため、認証情報を、IdPサーバーに寄せた運用をしております。 アクセスキー管理に悩まれてる方は、ぜひ、一度、IdPサーバから STS を取得する運用を試されてはいかがでしょうか? (※1) session mangerの概要、様々な使い方については、クラスメソッド様のブログに 多数記事 がございますので、session mangerってなんだっけ?という方は、そちらを見ていただくのがおすすめです。 (※2) AWS Tools for Windows PowerShell を用いると、標準ツールのみで 非常に簡単にadfsから認証情報の取得が可能 です。 (※3) 「 PowerShell からsession managerの開始ができない件」については、クラスメソッドさんが詳細を書かれていますので、詳細が気になる方はこちらをご参照ください。 PowerShellでSSMのポートフォワーディングを試してみた(けど駄目だったはなし) 執筆: @miura.toshihiko 、レビュー: @sato.taichi ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、美しい夜空を見渡す男の呪文です。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 魅惑的な女アニメ画(トゥーンレンダリング)編 長い呪文は切り捨てられる編 black silhuette of a man shot from the back sitting on the ground looking out into the sky colorful vibrant cosmos space, stars, nebula beautiful composition, beautiful soft purple blue lighting, cinematic lighting SIGMA art lens 24 mm F/1.4, ISO 1000, award-winning, concept art black cliff, sunrise まとめ 仲間募集 Stable Diffusionの過去コンテンツ black silhuette of a man 最初は、シンプルな黒いシルエット(silhuette)の男のPrompt(呪文)ではじめましょう。星を見上げる男は、黒いシルエットのほうが雰囲気が出ます。 今回のPrompt(呪文)はこちら。 black silhuette of a man 出力された結果はこちら。 シンプルなPrompt(呪文)ですが、意外と雰囲気が出ていますね。 shot from the back 星空を見上げる男は、後ろから撮影し(shot from the back)、背景にきれいな夜空が広がっているような構図にしましょう。今回は、shot from the backのみを追加します。 今回のPrompt(呪文)はこちら。 black silhuette of a man, shot from the back 出力された結果はこちら。 sitting on the ground 男を地面に座らせましょう。sitting on the groundを追加します。 サブジ ェクト(メインとなる描画対象)に動作を付け加える場合、 , 動詞のing ... を加えます。複数の動作を追加する場合も、 , 動詞1のing ..., 動詞2のing ... のように記述します。 今回のPrompt(呪文)はこちら。 black silhuette of a man, sitting on the ground, shot from the back 出力された結果はこちら。 looking out into the sky 男が空を見渡すようにしてみましょう。looking out into the skyを追加します。 今回のPrompt(呪文)はこちら。 black silhuette of a man, sitting on the ground, looking out into the sky, shot from the back 出力された結果はこちら。 colorful vibrant cosmos space, stars, nebula 空を美しい夜空にしてみましょう。the skyをcolorful vibrant(活気のある) cosmos space(宇宙空間), stars, nebula(星雲)に変更します。 今回のPrompt(呪文)はこちら。 black silhuette of a man, sitting on the ground, looking out into colorful vibrant cosmos space, stars, nebula, shot from the back 出力された結果はこちら。 beautiful composition, beautiful soft purple blue lighting, cinematic lighting 画像のクオリティを上げるためには、服装、背景、構図、ライティングの指定が必要です。 今回、服装は必要なく、背景はすでに指定済みなので、構図とライティングを指定します。 構図は、beautiful compositionで良いでしょう。 ライティングは、定番のcinematic lightingにbeautiful soft purple blue lightingを追加しました。 今回のPrompt(呪文)はこちら。 black silhuette of a man, sitting on the ground, looking out into colorful vibrant cosmos space, stars, nebula, shot from the back, beautiful composition, beautiful soft purple blue lighting, cinematic lighting 出力された結果はこちら。 SIGMA art lens 24 mm F/1.4, ISO 1000, award-winning, concept art これまで、画像のタイプを指定していませんでした。画像のタイプを指定しない場合、Stable DiffusionがPrompt(呪文)の内容から判断して決めます。今回は、写真にするために、 SIGMA art lensを指定しましょう。 レンズについて詳しく知りたい方は、 レンズ編 を御覧ください。レンズ編を書いた後の研究で、art lensをつけたほうが、出力結果のクオリティが若干上がることがわかったので、art lensを追加しています。 美しい夜空を広く撮りたいので、広角レンズとして24 mmの 焦点距離 を選びました。 暗い場所の撮影なので、明るいレンズ(F/1.4)を選び、 ISO感度 に1000を指定しました。 最近の記事で結構つけ忘れていましたが、アニメ以外の画像は、award-winning, concept artをつけたほうが、クオリティが上がります。 今回のPrompt(呪文)はこちら。 black silhuette of a man, sitting on the ground, looking out into colorful vibrant cosmos space, stars, nebula, shot from the back, beautiful composition, beautiful soft purple blue lighting, cinematic lighting, SIGMA art lens 24 mm F/1.4, ISO 1000, award-winning, concept art 出力された結果はこちら。 black cliff, sunrise the ground(地面)だと指定がアバウトすぎて、出力が安定しないので、一つ前の画像を見て思いついたblack cliff(崖)に変えることにします。 時間帯にsunrise(日の出)を指定して、美しい夜空と日の出が溶け込んでいる瞬間を狙います。 今回のPrompt(呪文)はこちら。 black silhuette of a man, sitting on black cliff, looking out into colorful vibrant cosmos space, stars, nebula, shot from the back, beautiful composition, beautiful soft purple blue lighting, cinematic lighting, sunrise, SIGMA art lens 24 mm F/1.4, ISO 1000, award-winning, concept art 出力された画像はこちら。 まとめ クオリティの高い画像を出力するには、 サブジ ェクト(描画対象)、背景、構図、ライティングを きちんと指定することが必要です。指定しなくても、たまたまクオリティの高い画像が出力されることもありますが、あくまでも「たまたま」です。 サブジ ェクト(描画対象)、背景、構図、ライティングは、常に意識しましょう。背景、構図、ライティングは、パターンが決まっているので、早めに覚えてしまいましょう。 次回は、 魅惑的な女アニメ画(トゥーンレンダリング)編 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの過去コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター