WEB+DB PRESS Vol.120

特集1 自作OS×自作ブラウザで学ぶ Web ページが表示されるまで

簡易的な UDP・HTTP サーバー・HTTP クライアント・Web ブラウザを、自分にも作れるかもと思えるくらいシンプルなコードで実装することで、普段使っている Web を支えている技術スタックを一気通貫に学ぶことができる。低レイヤーでもちゃんと WEB+DB PRESS にふさわしい特集。低レイヤーのプログラミングをやってみようかなと思えた。こんな特集をもっと読みたい。

特集2 最新 Vue.js 3 入門

Vue.js 3 で導入された Composition API を使っての開発は Vue.js 2 とは大きく違う開発体験。React に Hooks が登場したときのようなインパクトだ。Composition API の見た目は React Hooks にかなり似ていて、それだけ React Hooks がフロントエンド界に与えた影響は大きかったのだなと再認識した。

自分は React を使っているけど、Vue.js は React と違って、公式のルーティングライブラリや状態管理ライブラリが存在するのが羨ましい。

20周年記念企画 これからの Web 開発

技術の進歩は振り子ではなく螺旋、という話を思い出した。自分が注目するのは、分散 RDBMS だな。金さえ払えば無限にスケールする RDBMS は夢だけど、果たして実現するのかどうか。NewSQL には期待している。Spanner も NewSQL の一種らしいし。

メインで使っているクラウドは Azure なので、Cosmos DB は使ってみたい。無料枠大きいから個人開発で使えないか考えてみよう。

WEB+DB PRESS Vol.120

WEB+DB PRESS Vol.120

  • 発売日: 2020/12/24
  • メディア: Kindle

ぼくたちは勉強ができない(20)

あしゅみー先輩ルートはいきなり数年後に飛んで、成幸はすでに教師になっていた。離島に赴任したら、そこに研修医になったあすみがいた、という予想外の展開から始まった。大学生活すっとばすとはなぁ。あすみは髪が長くなって全然雰囲気が違う。大人っぽい。これは良いイメチェン。

そのすっとばした大学生活の間、2人は疎遠になっていたとはね。その理由がまさかまさかの、小美浪診療所が助けられなかった患者が成幸の父親だったとは。あすみ父と友人だったなんて、ここに来て何その設定。そりゃ、気まずくて会い辛くもなるわな。

それも、成幸が文字通り命をかけたおかげ(?)で、あすみは医者として一皮むけ、本当の恋人に。ついでにあすみ父も救われ、めでたしめでたし。恋人のフリしていた頃の成幸をからかうあすみは生き生きしていたけど、本当の恋人になってから照れる様子もまた尊い

麺酒場 朱拉

福岡麺本2020の表紙を飾っていたラーメンを出している『麺酒場 朱拉』が、ギリ会社から昼休みに行ける範囲にあったので食べに行ってきた。一番の売りは酸辣湯麺っぽくて、周りの客はみんな酸辣湯麺を食べていたけど、お目当ては表紙のラーメンなんで、中華そばに餃子とご飯のセットを注文。

f:id:griefworker:20201231115915j:plain

中華そばはふわっと柑橘系の香りが漂ってきて、スープはしっかりとしたガラの出汁が効いた醤油ラーメン。背脂が浮いているのは、こっちの醤油ラーメンには珍しい気がする。コクがあって、予想と違う美味しさだった。麺は慶史の細縮れ麺で、スープや具との絡みも良し。チャーシューは柔らかく仕込んであって、臭みも感じず美味しくいただけた。3枚あったのにペロリと平らげてしまった。チャーシュー麺にしてもよかったな。麺も美味しかったんで、大盛りでもよかった。期待以上。

f:id:griefworker:20201231115927j:plain

餃子は一口サイズで、外はカリッと、中はジュワトロ。餡がとろけて、舌を火傷してしまいそうなくらい熱々でなかなか美味。ご飯にも合う。餡はもっと肉肉しいほうが自分好みだけど、こういうのも悪くない。

f:id:griefworker:20201231115934j:plain

期待より美味しかったんで、酸辣湯麺とかも興味ある。酸っぱいの苦手だからどうだろう。いけるだろうか。酸っぱさ耐性に自信ないけど、また食べにきてもいいかなと思えた。ちょっと遠いので、行きか帰り、どちらか走る必要がありそうなのがたまにキズ。

r.gnavi.co.jp

2021 年の抱負

Happy New Year

謹賀新年。あけおめことよろ。さて、2021 年になったことだし、今年の抱負を書きたいと思う。

個人開発

去年に引き続き今年も個人開発に力を入れたい。今年こそ。

毎日コードを書く『Write Code Everyday』を今年も実践する。三が日はさぼってしまったけど…。毎日コードを書いて、それが積み重なっていけば、気付いたらずっと遠いところまで行けると信じたい。

ネタ自体はあるのに、どうしても Flutter や Unity などあちこち浮気してしまって、去年は進まなかった。

今年は自分が日常的に使うものから作るつもり。過去に作った IssueHub や Bitissues は、当時の自分が欲しくて、かつピッタリくるのが無かったので作った。実際普段使いしていたし。そういうアプリを今年は作ろうと思う。

使う技術は Xamarin で C# かな。やっぱり。Flutter にはだいぶ興味あるけど、Dart というのが抵抗感あって。.NET 6 で出る MAUI がいい感じになってくれるといいんだが。2020 年 4Q に出るはずだったプレビューが出なかったのは心配。

アプリをリリースできたら、なんとか収益化も行いたい。100 円でもいいので。0 を 1 にするのが一番難しいことを実感している。

英語

コロナ禍で今の会社の体力が持つか分からない。万が一の時の選択肢は多い方がいいので、外資系とかも選択肢に挙げられるくらいの英語力を身につけたい。

今年も Duolingo を中心にやる。今 3 周目をやっているので、これを 4 周 5 周とやりこんだらどうなるか。あと忘れてはいけないのがリスニング。英語のポッドキャストを去年より多めに聴いて耳を慣らし、少しでもネイティブの英語を聴き取れるようになりたい。日本人の英語なら結構聴き取れるようになっている気がするので、効果はあるのかも。

コミュニティ活動

新型コロナがどうなるか分からないので、しばらくは参加できないだろう。去年に引き続き、様子見。

その他

家族旅行とか行きたいけど、コロナが落ち着くまで無理だろう。

せっかく Nintendo Switch を買ったので、ゼノブレイド 1 と 2 はやりたい。リングフィットアドベンチャーも、2 日に 1 回くらいのペースで続ける。1 年の半分、180 日超でどれだけ体が変化するか期待。年末年始バクバク食べ過ぎて太ってしまった。正月休み明けたらリングフィット再開する。

2021 年やっていくぞ

個人開発と英語を去年に引き続きやっていこう。

2020 年ふりかえり

2020 年の締めくくりとして、1年を振り返ってみたいと思う。今年は2月くらいから新型コロナが流行し、年末になってもまだ落ち着いてなくて、それどころか第3波が来ている状況と、大変な1年だった。年の初めに立てた OKR の進捗は言わずもがな。

tnakamura.hatenablog.com

OKR は 3 つあって、1 つ目は個人開発。「Write Code Everyday」と「プロダクトを2つ以上リリースする」だったけど、プロダクトは 1 つもリリースできなかった。ライブラリは以前から作ってたやつなので、今年の成果とはちょっと違うし。コードは年の半分以上は書いたかな。GitHub の草は結構スカスカだけど、それは AtCoder のコードをコミットしていないせい。達成率としては 50% くらい。プロダクト出せていないのはダメだな。

今年は本業が忙しすぎて、帰ったら疲れ果てていることが多かったのもある。また、アプリを作ろうとしても、マネタイズできそうかどうかを最初に考えてしまって、サンプルから先に進まないことが多かった。「自分がお金払ってまで欲しいか」と基準にしてしまうと、生憎プログラマなので「頑張れば作れそうだからお金払わない」って考えてしまう。ゲームや漫画といったコンテンツ系は自分では到底生み出せないので、普通にお金払っているんだけどねぇ。ツール系はお金払ってまで欲しいというものがなかなか無い。プログラマのジレンマ。

2 つ目の英語に関しては Duolingo をほぼ毎日やった。途切れたのは 10 回もない。1 桁なはず。多分。今は英語の 3 周目に入っている。Duolingo は来年も続けるつもり。英語が身についたかどうかは正直わからない。コロナが落ち着いたら TOEIC でも受けてみようかな。

3 つ目のコミュニティ活動は、1 月に Fukuoka.NET の参加申込したはいいものの、運悪くインフルエンザにかかってしまい行けず。2 月に再び参加申込しようとしたら、その頃から新型コロナが流行り始めて中止。以降しばらくは、オフラインのコミュニティは軒並みストップしたのは承知の通り。一部のコミュニティはオンラインで復活しているが、オンラインでの参加は厳しい。19時とかだと、子供を寝かしつける時間だ。その時間に家で PC 開いて参加するのは厳しい。コミュニティに関してはオフラインの方がありがたかった。with コロナ時代のコミュニティはどうなることやら。

OKR 達成率は3割くらい。ダメダメだな。そもそも OKR達成したためしがないんだけど。新型コロナの流行があったので今年は仕方ない。2021 年こそはやっていきたい。

ゼルダの伝説 ブレス オブ ザ ワイルド

Nintendo Switch で最初に購入した『ゼルダの伝説 ブレス オブ ザ ワイルド』をクリアした。クリアしたといっても、ラスボスを倒したという意味で、祠とかをコンプリートしたわけではない。そこまでやり込む性格ではないので。

今まで FF やドラクエと言った典型的な JPRG ばかりやってきて、オープンワールドのゲームを初めてプレイする上に、ゼルダシリーズ自体も本作が初めて。10 年以上ブランクがある浦島太郎状態の自分にとって、予想以上に自由度が高くて驚きっぱなしだった。どの街に行くのも自由。どんな順番でストーリーを進めるのも自由。敵を倒さなくてもいい。アクション性の強い戦闘は得意じゃないので、遠目から弓で射ったり、逃げながら敵を各個撃破したりして進めた。ライフが心許なくて戦闘を避けたいなと思ったら、崖を登って迂回して敵を避けて進んだりできて、この自由度の高さは評判が高いのも頷ける。

最初はストーリーを順番に進めていたけど、シドを追いかけるところで、ゾーラの里に行く道中が思いのほか長く、何度も死んでしまった。そこから四神獣を解放するメインシナリオをいったん放置。祠をクリアしてライフを増やし、マスターソードを取得した。さらには、アクションに自信ないので防御力を高くしたいと思い、ハイリア装備を揃えて、大妖精の泉で最大まで強化。武器と防具を万全にしてからメインシナリオに復帰したおかげで、水も風も火もボスは楽勝だった。雷の神獣のボスだけは、素早い上に攻撃力も高くて一度やられてしまったが、戦い方が分かった2戦目はあっさり勝利。

ラスボスのガノン討伐は全回復の料理を作りためて挑んだので、時間こそかかったけど、特にピンチに陥ることはなく勝利をおさめた。ウツシエの記憶の場所は全部訪れて真のエンディングを見たので、祠コンプリートはしていないけど、これくらいでいいだろう。ゼルダ無双はもっとアクション要素が強いので興味はないかな。ゼルダの次回作が、今作のようなオープンワールドだったら買おうかなと思っている。それくらい満足度高かった。

ゼルダの伝説 ブレス オブ ザ ワイルド - Switch

ゼルダの伝説 ブレス オブ ザ ワイルド - Switch

  • 発売日: 2017/03/03
  • メディア: Video Game

Azure SQL Database に接続する WCF サービスの Windows コンテナを Azure Kubernetes Service で動かす

はじめに

Azure SQL Database に接続する WCF サービスを、Windows コンテナのプロセス分離モードで動かすところまで漕ぎつけた。

tnakamura.hatenablog.com

一連の実験もいよいよ今回で最後。Azure SQL Database に接続する WCF サービスを、Azure Kubernetes Service(以下 AKS) で動かすことに挑戦した。

WCFサービス作成

AKS で動かす WCF サービスを作成。前回の WCF サービスとほぼ同じ。名前空間とポートが違うだけ。接続文字列を環境変数で受け取るのがポイント。

using System;
using System.Data.SqlClient;
using System.ServiceModel;
using System.Threading;

namespace WcfAks
{
    class Program
    {
        static void Main(string[] args)
        {
            if (string.IsNullOrEmpty(TestService.ConnectionString))
            {
                Console.WriteLine("環境変数 CONNECTION_STRING を設定してください。");
                return;
            }

            var host = new ServiceHost(typeof(TestService));
            try
            {
                var binding = new NetTcpBinding();
                binding.Security.Mode = SecurityMode.None;

                host.AddServiceEndpoint(
                    typeof(ITestService),
                    binding,
                    "net.tcp://localhost:443/TestService");
                host.Open();

                foreach (var endpoint in host.Description.Endpoints)
                {
                    Console.WriteLine(endpoint.ListenUri);
                }

                Thread.Sleep(-1);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                host.Close();
            }
        }
    }

    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        string Test();
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class TestService : ITestService
    {
        public static string ConnectionString { get; }

        static TestService()
        {
            ConnectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");
        }

        public string Test()
        {
            try
            {
                using (var connection = new SqlConnection(ConnectionString))
                {
                    connection.Open();
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandText = @"SELECT @@VERSION";
                        return (string)command.ExecuteScalar();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                throw;
            }
        }
    }
}

WCFクライアント作成

AKS でホストした WCF サービスにアクセスするクライアントを作成。こちらも前回とほとんど同じ。名前空間とポートが違うだけ。 IP アドレスが現時点では不明なので、外から渡せるようにしておく。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WcfAks;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("ホスト名または IP アドレスを指定してください。");
                return;
            }
            var host = args[0];
            var factory = new ChannelFactory<ITestService>(
                new NetTcpBinding(SecurityMode.None),
                $"net.tcp://{host}:443/TestService");
            var channel = factory.CreateChannel();

            var result = channel.Test();
            Console.WriteLine(result);

            Console.WriteLine("Enter で終了");
            Console.ReadLine();

            ((IChannel)channel).Close();
        }
    }
}

namespace WcfAks
{
    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        string Test();
    }
}

Dockerfile 作成

Windows コンテナをビルドするために Dockerfile を作成。

FROM mcr.microsoft.com/dotnet/framework/wcf:4.8-windowsservercore-ltsc2019
WORKDIR /app
EXPOSE 443
COPY ./WcfAks/bin/Release/ .
ENTRYPOINT ["WcfAks.exe"]

AKS 上でホストとなる Windows ノードのバージョンが 1809 のようだったので、ベースイメージを 1809 のものに変更している。 WCF サービスの待ち受けポートが 443 に変わったので、EXPOSE で指定するポートは 443。

イメージをビルド

docker build -t tnakamura/wcfaks:1.0 .

リソースグループの作成

Azure 上に実験用のリソースグループを作成する。今回は Azure ポータルではなく、Azure CLI を使って作業してみた。

az group create --name wcfaks --location japaneast

Azure Container Registry の作成

AKS で動かすコンテナのイメージは Azure Container Registry(以下 ACR) から pull したいので、実験用の ACR を作成。

az acr create -g wcfaks -n tnakamuraacr --sku basic

作成した ACR にログイン

az acr login -n tnakamuraacr

tnakamura/wcfaks にタグを設定

予め作成しておいたイメージを ACR に push するために、タグを設定する必要がある。

docker tag tnakamura/wcfaks:v1 tnakamuraacr.azurecr.io/wcfaks:v1

ACR にイメージをプッシュ

docker push tnakamuraacr.azurecr.io/wcfaks:v1

AKS クラスタの作成

Windows コンテナを動かすための AKS クラスタを作成。

az aks create --resource-group wcfaks \
  --name wcfAKSCluster \
  --node-count 1 \
  --generate-ssh-keys \
  --attach-acr tnakamuraacr \
  --enable-addons monitoring \
  --windows-admin-password <password> \
  --windows-admin-username azureuser \
  --vm-set-type VirtualMachineScaleSets \
  --network-plugin azure

--attach-acr で先ほど作成した ACR をアタッチすることで、AKS が ACR からコンテナイメージを pull できるようになる。

Windows Serverノードプールを追加

Windows コンテナを動かせるのは Windows ノードだけなので、Windows ノードを追加する必要がある。

az aks nodepool add --resource-group wcfaks \
  --cluster-name wcfAKSCluster \
  --os-type Windows \
  --name npwin \
  --node-count 1

最初から Windows ノードを作成できるようになったらいいんだけどね…。

kubectlをインストール

Kubernetes の操作は kubectl を使う。

az aks install-cli

作成したAKSクラスタへの接続

az aks get-credentials --resource-group wcfaks --name wcfAKSCluster

Kubernetesマニフェストファイルを作成

docs.microsoft.com

上記のドキュメントのマニフェストファイルをベースに、イメージ名や環境変数、ポートを変更。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample
  labels:
    app: sample
spec:
  replicas: 1
  template:
    metadata:
      name: sample
      labels:
        app: sample
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": windows
      containers:
      - name: sample
        image: tnakamuraacr.azurecr.io/wcfaks:v1
        env:
          - name: CONNECTION_STRING
            value: "Azure SQL Database の接続文字列"
        resources:
          limits:
            cpu: 1
            memory: 800M
          requests:
            cpu: .1
            memory: 300M
        ports:
          - containerPort: 443
  selector:
    matchLabels:
      app: sample
---
apiVersion: v1
kind: Service
metadata:
  name: sample
spec:
  type: LoadBalancer
  ports:
  - protocol: TCP
    port: 443
  selector:
    app: sample

アプリケーションをデプロイ

kubectl apply -f wcfaks.yaml

イメージサイズが大きいせいで Pod が動くまで時間がかかるため、kubectl get pods --watch で確認しながら気長に待つ。

WCFクライアントから接続

まずは kubectl get services で、ロードバランサーの外部 IP アドレスを確認。

f:id:griefworker:20201221155709p:plain

判明した IP アドレスを引数に、クライアントを起動。

f:id:griefworker:20201221155726p:plain

SQL Server のバージョンが表示された。ということは、AKS で動いている WCF サービスが Azure SQL Database に無事接続できたことになる。

AKS クラスタ削除

用済みなので、リソースグループごと削除。

az group delete --name wcfaks --yes --no-wait

おわりに

Azure SQL Database に接続する WCF サービスの Windows コンテナを Azure Kubernetes Service で動かすことに成功した。Windows コンテナ関連の実験で設定していたゴールに、ついに到達。達成感ハンパない。

Kubernetes は入門したばかりなので、Kubernetes を習得することを次の目標にしよう