simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:job-system-cookbookからC#JobSystemの実例を確認

ちょっと前の私の記事
simplestar-tech.hatenablog.com
こちらでメッシュの変形やCubeの移動、画像処理などのサンプルをみつけたので、今回はそのサンプルの実装を確かめていきます。

Unity 2108.2.5f1
PackageManager にて
Burst 0.2.4-preview.26
Entities 0.0.12-preview.11
を有効化して動作確認しました。

ExampleScenes は 8つありますが、その中でも画像処理を行う WebcamProcessing のコードを追ってみます。
注意点として Webカメラから画像情報を引っ張ってくる処理と、その画像情報をテクスチャに適用する処理がメインスレッドの処理の99%を占めているので
その辺のコードを外してみるとパフォーマンスのすごさが体感できると思います。(いつか、カメラ画像情報の取得のオーバーヘッド減るといいね、画像処理研究してる人は50年ほど悲しんでいる)

コードを見ていて最初に衝撃を受けたのが次の SliceWithStride
Unity.Collections.NativeSlice_1.SliceWithStride - Unity スクリプトリファレンス

        m_Data = new Color32[m_WebcamTextureSize.x * m_WebcamTextureSize.y];
        m_NativeColors = new NativeArray<Color32>(m_Data, Allocator.Persistent);

        var slice = new NativeSlice<Color32>(m_NativeColors);
        m_NativeRed = slice.SliceWithStride<byte>(0);
        m_NativeGreen = slice.SliceWithStride<byte>(1);
        m_NativeBlue = slice.SliceWithStride<byte>(2);

NativeSlice は native 故に便利関数が用意できるんですね。
要素単位のオフセット指定で byte を取り出せる配列になるとか、C++でできた高速アクセステクニックが復活してきた

毎フレーム呼ばれるのが以下の関数

    void BurstExclusiveOrProcessing(NativeSlice<byte> r, NativeSlice<byte> g, NativeSlice<byte> b, ref JobHandle handle)
    {
        var redJob = new ThresholdExclusiveOrBurstJob()
        {
            data = r,
            threshold = m_ColorThreshold.r,
            widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
            height = m_WebcamTextureSize.y,
        };

        var greenJob = new ThresholdExclusiveOrBurstJob()
        {
            data = g,
            threshold = m_ColorThreshold.g,
            widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
            height = m_WebcamTextureSize.y,
        };

        var blueJob = new ThresholdExclusiveOrBurstJob()
        {
            data = b,
            threshold = m_ColorThreshold.b,
            widthOverLineSkip = m_WebcamTextureSize.x / lineSkip,
            height = m_WebcamTextureSize.y,
        };

        var length = m_NativeRed.Length;
        var rHandle = redJob.Schedule(length, 1024);
        var gHandle = greenJob.Schedule(length, 1024, rHandle);
        handle = blueJob.Schedule(length, 1024, gHandle);
    }

ThresholdExclusiveOrBurstJob を引数を r,g, b と変えながら3つ定義し、r, g, b の順でスケジュールしています。
Job 処理は 1024 画素ごとに行うように指定している

処理を理解するうえで重要なのは次のジョブの実装

[BurstCompile]
public struct ThresholdExclusiveOrBurstJob : IJobParallelFor
{
    public NativeSlice<byte> data;
    public byte threshold;
    public int height;
    public int widthOverLineSkip;

    public void Execute(int i)
    {
        bool operateOnThisPixel = (i % height) < widthOverLineSkip;
        bool overThreshold = data[i] > threshold;
        data[i] = (byte)math.select(data[i], data[i] ^ threshold, overThreshold && operateOnThisPixel);
    }
}

math.select は条件分岐を提供する Unity の新 math ライブラリの関数
どんなものがこれから登場するかは次のスライドの 33 p で予告されていた

www.slideshare.net

math ライブラリも NativeSlice もドキュメント整備はこれからって感じで、しっかりした説明にはまだたどり着けない

論理 XOR 演算子も復習しておかないと、すぐにはコードを読んでイメージできない
^ 演算子 (C# リファレンス) | Microsoft Docs

とりあえず ECS を抜いた C# Job System + Burst の書式で書かれた非常に短いサンプルですね。
理解できました。

メッシュ操作の方が気になるので、もう少しサンプルを見ていきましょうか

MeshComplexParallel というクラスの実装をみてます。

    NativeArray<Vector3> m_Vertices;
    NativeArray<Vector3> m_Normals;

    Mesh m_Mesh;

主な登場人物はこんな感じ(人ではないけど)

頻繁な更新を行うためにメッシュを最適化するのに

        m_Mesh = gameObject.GetComponent<MeshFilter>().mesh;
        m_Mesh.MarkDynamic();

        // this persistent memory setup assumes our vertex count will not expand
        m_Vertices = new NativeArray<Vector3>(m_Mesh.vertices, Allocator.Persistent);
        m_Normals = new NativeArray<Vector3>(m_Mesh.normals, Allocator.Persistent);

こんなことしてます。
マジかよ!!超いいこと知ってしまったぜ。(ていうか、最初から知っておくべき

頂点を更新するのにパーリンノイズを利用していたり、頂点自体が Vector3 と blitable ではないので Birst Compile は諦めている様子

    struct MeshModJob : IJobParallelFor
    {
        public NativeArray<Vector3> vertices;
        public NativeArray<Vector3> normals;

        public float sinTime;
        public float cosTime;

        public float strength;

        public void Execute(int i)
        {
            var vertex = vertices[i];

            var perlin = Mathf.PerlinNoise(vertex.z, vertex.y * vertex.x);
            perlin *= strength * 2;
            var noise = normals[i] * perlin;
            var sine = normals[i] * sinTime * strength;

            vertex = vertex - sine + noise;

            vertices[i] = vertex;

            normals[i] += Vector3.one * cosTime * perlin;
        }
    }

とても参考になります。
マインクラフト風の地形生成をこんな感じで Job を使って高速化してみたいですね

Unity:CEDEC2018のECSの発表から学ぶ

Unity にはコンポーネント指向という作法がここ10年間築かれてきましたが、他のゲームエンジンに並ぶような速度で計算するためには、そのコンポーネント指向をやめる必要があります。
ECSと呼ばれる新しいシステムを導入して、パフォーマンスを上げていくことになります。

ここまでECSでパフォーマンスが上がる仕組みをなんとなく理解してきたけど
ここで、もう一度 ユニティ・テクノロジーズ・ジャパンの発表資料を使って勉強していくことにします。

今回参考にする発表資料はこちら
「CPUを使い切れ!Entity Component System(通称ECS)が切り開く新しいプログラミング」
CEDEC2018

発表動画はそのうちこちらに追加されるのかな?
CEDECチャンネルYouTube版 - YouTube

これからは Unity を使う = ECS + Job Systems の書式でゲーム作る
という式が成り立つので、早いところ慣れておかないとUnityの現役エンジニアでも、一年後くらいに仕事無くなっちゃうと思います
人は誰しも常に勉強し続けて、最新技術に追従していかないと生きていけないんですよね

さて今回のECSへの移行ですが C++ で仕事してきた人たちがまた脚光を浴び、C# であまり見かけないポインタって何?、CPUにやさしいメモリ配置って何?って言ってた人が立場を失うドラマが各所で始まるわけです(ウソ)

発表スライド資料はこちら、簡単に読んで内容をまとめてみます。

www.slideshare.net

コンピュータが作られたのは第二次世界大戦中、ちょうど祖母が成人したころです。(祖母は今も元気に生きています。歴史浅い)
仕組みはずっと変わっておらず、集積率だけが劇的に向上して今のスマホがあります。(大枠でとらえると)
大枠でとらえたコンピュータの仕事は、CPU がメモリから情報を引き出して、足し算した結果をメモリに戻す作業なのですが
単純な処理を大量にこなす処理の中、まったく同じ計算式を実行するときに、一気に複数の式を実行する機能があります。
これには特定のメモリ領域に、決まったルールで情報を配置する必要があるのですが、要するにメモリに効率的にデータを詰めておけば、コンピュータの仕事が早く終わるというアイディアが存在します。

ゲームオブジェクトに共通の要素、例えば Transform Matrix や Position, Rotation 情報など、これらを更新する処理を対象に、
登場するデータをメモリに効率的に配置したいので、その配置処理に必要な情報を拾えるように ECS へ必要最低限の情報提供を行う必要があります。

ということで、その ECS が求める情報と、渡し方のコード書式を具体的に覚えることが、これからの Unity 開発時代を生き抜くことにつながります。

そこで、具体的には発表資料の 33p ~ 35p の部分の絵を覚えるのが良さそうです。
情報を行列と見立てた場合
Entity が列ベクトル(column)
Component が行列の要素(element)
System が行ベクトル(row)
CPUがアクセスするメモリの構造をイメージしながらコードを書く感じですね。

この行列の図から、Entity は Component を要素とする列ベクトルなので、プログラムでは Entity に Component を登録する記述が必要になります。
そこで Entity へ渡すComponet を列挙するコードが ArcheType 作成コードです。

ECS は全ての Entity がどのような Component を持つのかを把握してメモリ配置の効率化を行いたいので、すべての ArcheType の登録は EntityManager を介して行うことになります。
登録した ArcheType を指定して、初めて Entity を作成するコードが書けるようになります。

資料の 39p から 44p までの書式は
行列要素の Component 定義
行列の列ベクトルの Entity の定義
その Entity の作成
作成した Entity の Component へ値の代入 (SetComponentData)
となっています。

EntityComponentSystem では動的に Entity を定義して利用することになっていきます。
プログラミング時のメンタルモデルを変えないといけないですね。(型は基本コンパイル時(静的)に決めていたと思いますので)

BurstCompiler を有効化する時の属性が
[BurstCompile]
とわかりやすくなっている。(Jobの属性に追加するのは変わらず、昨日見た Unite Europe 2017 動画だと、もっと長いやつだった)

Job 構造体の Execute 関数内部のみが高速化用のコードに変換されるが、参照型にアクセスできない、static 変数にアクセスできないという制約あり(逆に副作用とされる競合状態を事前に避けられるのでうれしいかも)
ところで、デバッグ時の Debug.Log を Execute 関数に仕込みたいですよね、その気持ちわかる!ということで関数の属性に [BurstDiscard] を与えると、Burst するときに除外されるので、非 Burst のデバッグ時に利用できることが紹介されています。

マルチスレッド処理のおさらい
コンテキストスイッチ
いつも仕事の効率化について使う単語だけど、CPUに割り当てるスレッドの切り替えも同じ単語使う

そして最重要なのが ComponentDataArray

残念ながら、このパワポ資料単体では ComponentSystem の動きをイメージしきれません。
いったんイメージ作成のための要素知識を作成する作業として次の記事を読んでおきます。
tsubakit1.hateblo.jp

さらに残念なことに、[Inject] などの属性のイメージがまだつかめないことがわかりました。

パワポ資料に戻って、コンポーネント指向のこれまでの実装と、ECS によるこれからの実装の変化についてみていきます。
MonoBehaviour → JobComponentSystem
MonoBehaviour.Update 関数 → JobComponentSystem.OnUpdate 関数

行列で ECS を表した時、行ベクトルが System であることを示しました。
System は複数の Entity から抽出した同一の ComponentData 配列であることをイメージできます。

その ComponentData 配列こそ ComponentDataArray であり、具体的に利用するために ComponentSystem クラス内に注入(Injection)します。(なんか表現エロいですね)
正確には複数の ComponentDataArray を Group として定義して、その Group に [Inject] 属性を与えて注入することを宣言します。
この ComponentDataArray の Group の Injection が只者じゃないってことで、発表資料では面白いと紹介されています。

実装例では ComponentDataArray と IJobParallelFor の組み合わせで、Group の Injection の代わりに Job の依存関係を記述することで示されています。
ComponentDataArray からの読み出しと書き込みの例が示されていますが

ECS 学習中に、Job System との連携コードが示されて、急激に認識負荷が上昇していますね。
ここもっと優しい解説が必要なんじゃないかな?

そこで、私の解説を追加します。
Job の依存関係は前回の記事にて
[UpdateAfter(typeof(DamageSystem))]
といった属性を ComponentSystem クラスに設定することで解決できると示しましたので、これで行列の行ベクトルの処理の実行順を ECS に教えることができます。
この記事を書いた後に、とても理解の助けとなる解説記事が作られましたので紹介します。
tsubakit1.hateblo.jp
プロファイラからもEntitySystemの実行順が確認できるのは助かりますね。(精神が)
さらに OnUpdate 関数内の Job の Schedule にて、このクラス属性の依存関係を参照できるように
AddDependency(job.Schedule(m_transforms, GetDependency()));
と ComponentSystem 側から Job Handle を取得して、ECS と Job System との融合を果たします。

やっと書式に納得いく理解できた。

あとは行列の要素である Component にどんな型が指定できるかの解説が続きます。
IComponentData で書ける型は blitable なもののみ
blitable ってのは、よく DllImport などで渡しできる型が限定される例と同じで、メモリサイズが確定する型のみ指定可能
ゆえに NativeArray もだめです。

高度な解説ですが、Job 内の Execute 処理中に Entity を生成したいという要望にも応えるギミックがあることが示されています。
具体的には EntityCommandBuffer と BarrierSystem の存在です。
Job の中での Entity 生成は、いったんその Job がすべてのスレッドで完了し終えた時に、Entity の生成を行うということで
コードを書いているときに、やっぱりスレッドの動きを想像しながら書かなければいけません。(ここはこれまでのマルチスレッドの記述で気を付けていたことと同じですね)

この辺の書式は使っていかないと、感覚をつかみづらそうですね
すべての Job を停止してから、キューに積まれたコマンドを実行する遅延実行の機構が BarrierSystem で
そのコマンドのキューが EntityCommandBuffer と覚えておきます

あとはゲームロジックから見た ECS ですね。
OnUpdate で一気に複数の Entity の ComponentData を処理することになりますが、やっぱり特定の Entity について特別に処理を分岐したいじゃないですか。
例えば大量のミサイルの追尾となったとき、ミサイルが追尾する対象は Entity なので、その Entity の ComponentData を取得したいケース
エンティティから Component Data を取得可能とはそういうことで
ComponentDataFromEntity が用意されています。
ほかにも、Entity が存在しているかどうかをExists 関数を用いて Job 内で見ることができるので、なんだかんだゲームオブジェクトへの参照が Job 内で使えなくても、ゲーム特有のオブジェクト依存のロジックが組めそうです。

ゲームロジックをどうしても Job で書きたい、ゲームオブジェクトへの参照を Execute 関数内で実現したい、そんなときの書式紹介もありました。
static 変数へのアクセス制限があるので BurstCompile をあきらめることになりますが、Static 変数として定義したクラスのインタフェースを介してゲームオブジェクトの参照を利用したコードを Job 内で実行することができます。

後半は汎用性ではなく、ゲーム特化のテクニックの紹介ですね、実装時に困ったら参考にしてみようと思います。
こんなところでしょうか?

結局作りやすさは従来のコンポーネント指向で、これは無くならずに
今後パフォーマンスが求められる場面で ECS が導入されていくことになる未来が見えてきました。

一度コンポーネント指向で作り、パフォーマンスの負荷が高い場所について、 ECS への移行ができないかを見極める眼力が今回の勉強で備わった気がします。

Unity:C# JobSystemとBurstCompilerそしてECSこと(EntityComponentSystem)の概要

この三つがそろった時、Unity は完全体となって、Unreal は死ぬという噂が流れるほど
Unity のパフォーマンスを向上しつつ、競合状態などを起こさないように安全にコーディングできるようになるとのこと

さて、前回に続いて C# Job System の書式を学んでいます。以下のドキュメント読んでますが
github.com

そのドキュメントにまずは次の動画を事前に見ろ!(意訳)ってありましたので、見ました。
www.youtube.com

内容をざっくりまとめると

1.C# Job System の書式解説
具体的には、NativeArray をはじめ、NativeList, NativeSlice, NativeHashmap, NativeMultiHashmap, NativeMultiHashmap.ConcurentWriter など
みんなが C# でよく使ってきた List, Dictionary に相当するものを unsafe に扱えるものを C# 用に用意したよというもの(すごい、Unity 以外でも欲しい)
そのほか Job として何らかの C# コードを実行するには IJob を継承する struct を定義して Execute に処理書けば動くよ
普通はマルチスレッドに分散するよね、そんなときは IJob の代わりに IJobParallelFor を使うよ
超重要なことだけど、依存関係は Job の Schedule を切ったときに取得できる JobHandle を利用することで、安全に順番に Job を実行できるよ
お魚の群れのシミュレーションコードも、ここまで解説した基本の通りになっているよ

2.BurstComplier (C# Job Compiler)の使い方
まず速くなるのは

No virtual functions
No reference types
No GC
Native Containers
SIMD auto -vectorization
Preciton control (Low, Med, High)

の強い制約をもって最適化するためです
Compiler の恩恵を受けたければ、先ほど紹介した Job 構造体の attribute 宣言に
[ComputeJobOptimizationAttribute(Accuracy.Med, Support.Relaxed)]
を書くだけ(会場から笑い)

3.これまでの書式からの書き換えの簡単さの紹介
パフォーマンス気にしているなら Update を MonoBehavior ごとに書かずに、どっかにまとめて for 文を回すようにしてきたと思います。
みなさんそうしてます?(会場:はーい)クールだね
そんなギミックコードの Update 内の処理を Job の Execute に置き換えるだけで、ほら、既存のコードの高速化も超導入しやすいでしょう?(拍手)

4.ECS(EntityComponentSystem)
みんなが今まで書いてきたコンポーネント指向のコードは

GetComponent<Transform>()

といった形でメモリのあちこちから参照を引っ張ってきて、コンピュータは最適化に困っていたわけです。
解決するために ECS の書式に書き換える必要があるわけですが
具体的にはデータだけが定義されているような MonoBehavior は IComponentData を継承する struct に差し替えましょう
出現しているゲームオブジェクトをまとめて処理していたようなクラスは ComponentSystem を継承するクラスに差し替えて

List<Transform>

フィールドは

[InjectTuples]
public ComponentArray<Transform>

に書き換えて、C++でいうところのポインタ配列にして、連続でメモリアクセスできる状態にするのです。
ComponentSystemクラスの属性に
[UpdateAfter(typeof(DamageSystem))]
といった形で、さらに別の ComponentSystem との依存関係を定義できます。
驚いてほしいのはここから、ComponentSystem を JobComponentSystem に書き換えておけば OnUpdate 処理にて Job を作成し
AddDependency(job.Schedule(m_transforms, GetDependency()));
と書けば、C# Job System の書式説明で書いた Complete を呼ばなきゃ、みたなこともなく競合が起きなくなるし、これが最適化処理に響いて極めて高速化するわけ。
イメージとしては低レベルレイヤーですべての会話が成り立つという感じで、コードは競合状態を気にせず値変更とか書けるようになる!(会場:すごーい拍手)ハッピー

5.質疑応答
ネイティブ同士の会話は聞き取れないー

1時間の動画だけど、C# Job System, Burst Compiler, ECS などのキーワードと実装イメージの連絡を行いたいときは、こちらの動画をじっくり視聴することをオススメされるのもわかる気がした

さーて、サンプルコード読んでいくぞー
今なら読める気がする

Unity:安全な並列処理をする C# Job System について学ぶ

Unity の GDC2018 の英語発表見てるけど、長いな
まずは椿さんことUnityエヴァンジェリストの山村さんのブログ読んでどういう話なのか、知識を増やします。
tsubakit1.hateblo.jp

確かに、過去に Task とスレッドセーフキューを使った実装で、大量のブロックの相互作用をメインスレッドを停止させずに動かしたことありましたね。
simplestar-tech.hatenablog.com

これは確かにメインスレッドは結構余裕をもっていて、バックグラウンド処理が休みなく働いているイメージでした。
C# Job System はメインスレッドも休みなく働くようにスケジューリングできそうです。

Burstコンパイラ
(出典は山村さんのツィート)
scrapbox.io

1Tweetで分かる?Burstコンパイラ
・Mono、IL2CPPに並ぶ第三のコンパイラ
・厳しい条件指定のあるC#下(No GC,Noクラス,Noボクシング,No 例外処理)で最適化したアセンブラを吐く
・吐いたアセンブラはプレビュー出来る
SIMD で最適化 ・数字の精度を落としてさらに高速化

確かに高速になる機械語に翻訳してくれそうなルールですね。

この Burst コンパイラですが
手元の Unity 2018.2.2f1 は、プレビュー版ですが、Package Manager から有効化することができます。
ってことは、使い始めることは出来るってことですね(高速化試したい)

f:id:simplestar_tech:20180821073030j:plain

きっとそうだろうと思ったけど C# Job System では Collider や gameObject が取得できない
え、じゃあ RayCast とかもだめ?

それが C# Job System 用に RaycastCommand が作られているそうです。
Unity - Scripting API: RaycastCommand

なるほど、書式イメージは

1.入力作成
2.並列処理
3.結果利用

の3ステップですね。

■ NativeArray

あ、もしかして GCHandle.Alloc, handle.AddrOfPinnedObject を使わなくてもポインタ利用できる配列ってやつですかね?
ちょっと前 OpenCVC++のまま Unity で使う例を示した時に、WebCamTexture を cvMat として扱う時に使ってたやつです。
simplestar-tech.hatenablog.com

fixed いらずで unsafe ポインタを取得できるって、やるぅ!(C++のようにメモリの順番を使ったコード書ける!やった)
Unity - Scripting API: Unity.Collections.LowLevel.Unsafe.NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr

OnEnable で永続確保、OnDisable で Dispose による開放を行うのが良さそう

■ IJobParallelFor

並列処理するジョブはこのインタフェースを継承して、処理を実装するだけでよい
後は以下に紹介されている例を参考に Schedule, Complete の呼び出しで並列処理が完了する
Unity - Scripting API: IJobParallelFor

ひとまず書式は学べたし、並列処理を行えることも確認できました。

後半の
メッシュの変形やCubeの移動、ポイントクラウドや当たり判定
のデモの紹介が気になった。
github.com

今度はこちらを読むことにします。

AWS:Webページを作ってみる

インスタンスに独自の url を設定できたんだから、その url で Web ページを見てみたくありませんか?
そこで、次の記事を参考にしてみることにしました。

qiita.com

yum update コマンドまでは成功したのですが…

install nginx コマンドには失敗

Amazon Linux Extras を使ってみない?という旨のメッセージが表示される。

Amazon Linux Extras とは何ですか?
Amazon Linux 2 に関するよくある質問

Extras は、安定したオペレーティングシステムで新しいバージョンのアプリケーションソフトウェアを利用可能にする Amazon Linux 2 のメカニズム
Extras は、OS の安定性を確保しつつ、最新のソフトウェアを利用できるようにするうえで役立ちます
Extras の例には、Ansible 2.4.2、memcached 1.5、nginx 1.12、Postgresql 9.6、MariaDB 10.2、Go 1.9、Redis 4.0、R 3.4、Rust 1.22.1 などがあります

もう少し、このメカニズムについて調べて導入してみますかぁ

最小のドキュメントとして読むべきものはこちら
docs.aws.amazon.com

ここの Extras Library (Amazon Linux 2) 項目を参考に手を動かしてみた、まずは list で使えるものを列挙します。

amazon-linux-extras list

おお 21 項目のうち index 3 に nginx という Web ページ作るツールが見つかった
で?

sudo amazon-linux-extras install nginx1.12

こうしたらインストール成功した。
もともと docker はインストールされていたっぽいな
起動に関しては次のコマンドを打ったら、動くらしい(起動書式ってやつ?)

sudo chkconfig nginx on

あとは http の 80 ポート TCP で通信許可するようにセキュリティーグループにルール追加してきます
一応追加する前にアクセスすると?
アクセスできない
セキュリティーグループに HTTP の許可を与えると
アクセスできない

あ、もしかして起動コマンドは先に実行しておくべき?

sudo service nginx start

はいそのとおりでしたー、アクセスできました!
Welcome to Nginx on Amazon Linux のページが表示された

あとは scp というセキュアコピーのプロトコルWindows から安全にファイル操作できたらいいな

ということで WinSCP ソフトを入れるぞ
winscp.net

url とユーザー名 ec2-user で
設定にて privatekey.pem を指定したら OpenSSH 形式だから putty 形式に変換して保存までしてくれて
その putty 形式の privatekey.ppk ファイルを指定したら SCP 通信できることを確認できました。

あと、nginx のディフォルトの htmlファイル群のパスはどこでしたっけ?
/usr/share/nginx/html
ここに index.html があるのがディフォルト設定です。
設定を変更するには /etc/nginx/nginx.conf を編集します。

よし、これで AWS で Web ページを作れたし、編集も自由です。
あとは html の使い方のみ書式を見ていけば完了!

AWS:独自ドメインの購入とインスタンスのIPアドレスとの関連付け

AWS の一つに Route53 というものがある(なんで53なんだ?)

やりたいことは、ついさっき作成した Amazon Linux 2 の AMI からインスタンス化したリソースに
独自ドメインを使った url を割り当てて、その url を使って ssh 接続できるようにしたいというもの

独自ドメインはお金かかるのですが、だいたい 1000円~2000円くらいで 1年間の使用ができる。
ドメインですから、その前に適当な文字列入れて幾千もの url を作成することが可能になります。

さて、具体的な手順だけ知りたくなったので、記載場所を探したところ、ここに書かれていました。

docs.aws.amazon.com

ここに書かれてる手順を踏むだけで、30分後には有効なドメインを取得できました。

インスタンスの IP アドレスと、このドメインの適当な url を関連付ける方法は以下のサイトを参考にしました。

exrecord.net

具体的には、ホストゾーンにレコードセットを作成(A - IPv4 のレコードセット)
そこの Valueインスタンスの IP アドレスを貼り付けるだけで

目的の url を使った ssh 接続ができることを確認しました!

その時の cmd でのコマンド

ssh -i privatekey.pem ec2-user@dokuji.domain.net

AWS:AMIの作り方4-テンプレのAMIで作ったインスタンスから作成

ここまで AMI の作り方の記事を参考に見てきましたが、いよいよ S3 のバケットに AMI に関するファイルを出力する段階になって
ec2-bundle-vol コマンドをキーワードに調べたんですけど

>インスタンス内から ec2-bundle-vol コマンドを実行して、Amazon S3 にアップロードするバンドルを準備します。

インスタンス内から

はい、ということで最初は AWS が提供している AMI を使っていきましょう。

Linux を触るのですけど、二つあって困る

これは、何が違うの?
間違ったの選んだら終わるの?

Amazon Linux 2 のご紹介

既存のAmazon Linuxの後継となるOS
>Amazon Linux 2 は、アマゾン ウェブ サービス (AWS) 上で最適なパフォーマンスを発揮できるように調整された LTS Kernel (4.9)、systemd のサポート、および最新ツール (gcc 7.2.1、glibc 2.25、binutils 2.27) を使用した近代的な実行環境を提供
>PythonMariaDB、Node.js などの一般的なソフトウェアパッケージのより新しいバージョンを含む追加のソフトウェアを、Amazon Linux Extras リポジトリを使用してインストールできます
Red Hat Enterprise Linux 略して RHEL 7 ベースで作られるようになったのが Amazon Linux 2 だとか

「LTS」とは一体何?
長期サポート(LTS)

サポート期間が、従来の2年間から6年間に延長されることになった
通常と比べて長い間サポートされる
Linux KernelのLTSサポート期間が6年に伸びるということはメーカーにとって非常にうれしいニュース

なるほど、これから長いことサーバーを運用していくなら TLS 版のカーネルを利用するのがいいって話か
では Amazon Linux 2 を使っていいんじゃないですかね。

AWSインスタンス作成に進みますが
VPC はディフォルトで一つありますね、なんか vpc-f6f48xxx みたいな適当な名前のやつ
172.31.0.0/16 の CIDR ブロックが指定されていました 172.31.0.0 ~ 172.31.255.255 までのプライベートIPアドレス範囲か?
IPアドレスはクラスBの範囲だもんだが
なんでこんな IPアドレス範囲にしなければならないのかの基準の考え方が不明

まず CIDR は、ブロック単位のIPアドレス割り当て方式よりも、狭い範囲のIPアドレス割り当て範囲を指定できる仕組み
/16 ってのは 実は 2ブロック指定と同じ、8x8だから、そう /16 は固定 bit 数を指定していて、32bit に対する残りの 16 bit の 0.0 ~ 255.255 の範囲を指定するものだそうだ
/24 とかにすれば 0 ~ 255 の範囲を指定することになる、もうちょっと増やすには /23 とかにすれば 0.0 ~ 2.255 と、割り当て範囲を 2倍にするように指定することが可能だそうだ

今なら VPC の話を記憶しやすくなってきました、VPCで設定するのは全部プライベートIPアドレスなので、超自由
docs.aws.amazon.com

そして、適当に IP アドレスの範囲を CIDR 書式で指定しても
AWS によって必ず 5 つの IP アドレスが予約される
0: ネットワークアドレス
1: VPC ルーター用に AWS で予約
2: AWS で予約されています
3: 将来の利用のために AWS で予約されています
255: ネットワークブロードキャストアドレス、予約されている

ということで、VPC 内にインスタンスを作った場合は 4 ~ 連番でプライベート IP アドレスが振られるんじゃないかな?って予想が立ちました。

さて、インスタンス作成に戻って
VPCとサブネットは AWS がディフォルトで用意してくれていたものを選ぶようになっています。
今のところ VPC を切り替えなきゃいけないということもないので、そのままにしました。

インスタンスタイプでスペックが決まりますが、インスタンス数1, コア数1, メモリ1GB
次にストレージを選ぶのですが…Amazon EBS ボリューム?

Amazon EBS ボリューム - Amazon Elastic Compute Cloud
EBS ボリュームは、EC2 インスタンスの運用状況から独立した永続性を持ち、インスタンスにアタッチして利用する
メリット1:作成したボリュームは、同じアベイラビリティーゾーン内の任意の EC2 インスタンスにアタッチできます。別のインスタンスからストレージを利用するのに便利、インスタンス壊れてもストレージ残るので安全
メリット2:インスタンスがシャットダウンされてもデータが維持される限り、ボリュームの使用料が発生する。一緒に削除オプションはディフォルトで入っている
メリット3:暗号化は、すべての EBS ボリュームタイプでサポート、今回は使わない
メリット4:Amazon EBS は、Amazon S3 ボリュームのスナップショット (バックアップ) を作成し、ボリューム内のデータのコピーを EBS に書き込む機能を備えています。
メリット5:柔軟性
EBS ボリュームは、実稼働環境での設定変更をサポートします。サービスを中断せずに、ボリュームタイプ、ボリュームサイズ、IOPS 容量を変更できます

メリット5がすごいね、ハードディスクの容量が足りない状況で足せるのか、いいね。

ところで ストレージの性能指標 IOPSってなに?
Input Output Per Second のこと、100 はかなり遅い、10000 はかなり速い
ディフォルトでは最小の 100 だった

で、そんな EBS ボリュームを 8GiBでストレージに設定

次はタグをつけるかどうか聞かれる
いや、タグだけじゃ具体的に何なのかイメージできないよ
docs.aws.amazon.com

なるほど、めちゃめちゃインスタンスを立ち上げまくった場合に管理とかリストアップとか大変だから、プログラムのリスト内要素のキー名として、いくつかタグ付けておくと管理楽だよって話ですか

ほんと、マシンがプログラムの配列の要素として機能する社会を表す機能ですね。

セキュリティグループの設定で ssh 接続の IP アドレス制限ですが、マイIPを選択すると、今の家の環境のグローバルIPアドレス教えてくれるんですね
がっくし、じゃあ今後自分の IP アドレスを知るときは AWS のセキュリティグループの設定機能を使いますか

よし、これで SSH 接続できるのはこの家からのみになるはず、インスタンスを作って試してみます。
ec2-user がディフォルトユーザーであるとドキュメントにあったので、Amazpn Linux 2 の AMI から作ると ec2-user しか指定することができない

ssh -i privatekey.pem ec2-user@13.113.xx.xx

確かに実家からアクセスできた

そしてちょうど自宅に戻るので、自宅で同じようにアクセスしたところ、しばらくしてタイムアウト
なるほど!

そして、自宅のマイIPからの接続ルールを SSH に追加して、即座に自宅から SSH 接続に成功することを確認しました。
やったね、これでやっと安全に GNU / Linux を触れるようになった