scent-yのブログ

学んだことや感じたことの備忘録

「SQLアンチパターン ジェイウォーク(信号無視)」を読んで

学びの備忘録

  • 「多対多」の関連を表現する交差テーブルの作成を避けてカンマ区切りのリストを作成するのはアンチパターン(作中ではジェイウォーク(信号無視)と表現している)
    • 全ての外部キーが文字列連結されて一つのフィールドに格納されていると、等価性の比較ができなくなり文字列に対するパターンマッチが必要になり、クエリの作成が難しくなる
      • パターンマッチ構文はデータベース製品によって異なる
      • インデックスを使うメリットを得られない
      • ユーザーがさまざまな値を入力できるのでデータがゴミだらけになる危険性がある
  • ジェイウォークを避ける解決策は、多対多の関連をあらわす交差テーブルの作成
    • メリット
      • 外部キー制約によって参照整合性を保持できる
      • SQLのデータ型によって入力内容を制限可能
      • 外部キーにインデックスを貼ることでパフォーマンス向上(postgresでは暗黙でインデックスが作成されないので注意)

参考

O'Reilly Japan - SQLアンチパターン

oapi-codegen に関して備忘

OpenAPI で Go コードを生成するために使用している oapi-codegen に関して備忘

  • oapi-codegen は OpenAPI 定義ファイルからサーバーサイドのボイラープレート、API クライアント、API モデルを生成する
  • サーバーは Chi や Fiber などをサポートしている
  • oapi-codegen がここで全ての型を生成するため、可能な限り#/components/schemas内で定義することが推奨されている
  • API モデルはcfg.yamlに下記を追加することで生成される
package: onlymodels
output: only-models.gen.go
generate:
  models: true
  • 参照されてないオブジェクトはデフォルトでは生成されないが、yaml の設定ファイルに下記を追加することで、生成可能になる
package: onlymodels
output: only-models.gen.go
generate:
  models: true
output-options:
  skip-prune: true // add 
  • OpenAPI 定義が大規模になった際、Import Mapping を利用することで複数ファイルに分割することが可能になる
  • 下記のように定義することで、他のファイルのスキーマが参照可能になる
components:
  schemas:
    User:
      $ref: '../common/api.yaml#/components/schemas/User'
  • cfg.yamlに Import Mapping の設定がされてないのに他ファイルの定義を参照しようとすると、oapi-codegen から please provide the known import for this reference using option --import-mapping のような生成エラーメッセージが返却されるので、下記のように定義する必要がある
# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
package: admin
output: server.gen.go
generate:
  models: true
  chi-server: true
output-options:
  # to make sure that all types are generated
  skip-prune: true
import-mapping:
  # for a given file/URL that is $ref'd, point `oapi-codegen` to the Go package that this spec is generated into, to perform Go package imports
  ../common/api.yaml: github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common
  • nullable な型を定義したい場合は下記で指定可能で、ポインタ型として生成されるが、フィールドが送信されてない場合と null として送信された場合を区別することができなかった
S:
  type: object
  properties:
    Field:
      type: string
      nullable: true
    required: []
type S struct {
    Field *string `json:"field,omitempty"`
}
// add output-option
output-options:
  nullable-type: true
// generated 
type S struct {
    // note that there's no pointer here, just `omitempty`
    Field nullable.Nullable[string] `json:"field,omitempty"`
}

参考

GitHub - oapi-codegen/oapi-codegen: Generate Go client and server boilerplate from OpenAPI 3 specifications

想定外の relation does not exit に遭遇した

ローカルマシンで Docker コンテナで postgres を起動していて コンテナから起動したサービスで postgres のコンテナにアクセスしリスト取得する箇所で、relation {table_name} does not exist. が発生した。 postgres コンテナに入って psql コマンドで確認したところ、該当のテーブルは存在しており、謎な状況だった。結論としては凡ミスで、postgres のコンテナと同じ port でローカルマシンで postgres を起動しており、サービスからコンテナの postgres ではなくローカルマシンの postgres を参照してしまっていたのが原因だった。視野が狭くなっているとこういう事にすぐ気付かなかったりするので、備忘として記録に残す。

Go の基本復習 ~interface~

Go 言語の基本を復習のため記載していく。インターフェース編。

Go のインターフェースは持つべきメソッドを表現するための言語機能。Go ではインターフェースの型を持つ構造体を定義することで、構造体に持たせたいメソッドを表現することが可能。他の言語のように、インターフェースを満たすために implements のようなキーワードは不要。

Go では構造体がインターフェースを満たすメソッドを実装しているかどうかは、インターフェースの型を持つ変数に構造体のポインタを代入すると自動的に確認される。

// インターフェース
type TestWriter interface {
    Write(body string)
}

// インターフェースを満たす構造体
type testWriterImpl struct{}

// 構造体のインスタンスのポインタをインターフェース型の変数に代入
var _ TestWriter = &testWriterImpl{}

// インターフェースで定義されているメソッドを構造体に定義することで、インターフェースを満たす
func (t testWriterImpl) Write(body string) {
    // TODO impl
}

GoLand で 例えば io.Writer インターフェースの実装を確認したい場合、`移動 -> 実装` から確認できる

kubernetes 入門

技術書の備忘録を記録

  • k8s クラスタ
    • k8s のさまざまなリソースを管理する集合体
  • Node
    • クラスタが持つリソースで最も大きな概念。Docker コンテナのホスト。k8s でコンテナをデプロイするために利用される
    • k8s クラスタには全体を管理する Master が一つは配置される。クラスタには Master Node と Node が存在する
  • Master を構成する管理コンポーネント
    • kube-apiserver
    • etcd
      • キーバリューストア
    • kube-scheduler
      • Node を監視し、コンテナを配置する最適な Node を選択する
    • kube-controller-manager
      • リソースを制御するコントローラーを実行する
  • Namespace
  • Pod
    • コンテナの集合体の単位。少なくとも一つのコンテナを持つ。同一 Pod 内のコンテナは、全て同一の Node に配置される
  • ReplicaSet
    • 同じ Pod を複数生成、管理するためのリソース
    • 指定された Pod 数の確保や新しいバージョンへの Pod の入れ替え、以前のバージョンへの Pod のロールバックといった重要な役割を担う
  • Deployment
    • アプリケーションのデプロイの基本単位となるリソース。ReplicaSet は同一仕様の Pod を管理・制御するためのリソースで、Deployment は ReplicaSet を管理・操作するために提供されているリソース
  • Service
    • k8s クラスタにおいて Pod の集合(主に ReplicaSet)に対する経路やサービスディスカバリ(APIへの接続先が動的に変わる際に、クライアントは接続先を切り替えることなく一貫した名前でアクセスできるようにした仕組み)を提供するためのリソース。
  • ClusterIP Service
    • デフォルトで作成される Service が ClusterIP Service。クラスタ上の内部 IP アドレスに Service を公開できる。ある Pod から別の Pod 群へのアクセスは Service を介して行うことが可能。外からのリーチは不可
  • NodePort Service
    • クラスタ外からアクセスできる Service。 非マネージドで k8s を運用する場合、Master が単一障害点にならないよう、マルチ Master で3台配置するのが一般的
  • Ingress
    • 外部からのアクセスを制御し、クラスター内のサービスにルーティングするためのリソース。HTTP や HTTPS リクエストを適切なサービスに転送する。外部からのアクセスを一元的に管理することが可能

参考 Docker/Kubernetes 実践コンテナ開発入門

Docker復習 Dockerfileからイメージを生成しコンテナを起動

以下、備忘録。

  • Dockerfile作成
# Ubuntuベースイメージを指定
FROM ubuntu:latest

# パッケージの更新とhttpdのインストール
RUN apt-get update && \
    apt-get install -y apache2

# コンテナが起動したときに実行されるコマンドを指定
CMD ["apache2ctl", "-D", "FOREGROUND"]
  • Dockerfileからイメージ生成
docker build -t sample:01 ./ -f Dockerfile
  • コンテナの起動
# host OSの8900ポートを指定
docker run -d -p 8900:80 sample:01
  • CMDとENTRYPOINTはコンテナ起動時の挙動に違いがある。CMDで指定したコマンドは docker run 実行時にコマンドを指定した場合にそれで上書きされるが、ENTRYPOINTだとコンテナ起動時に常に実行される。

Docker イメージに関して復習

以下、備忘録。

  • Dockerイメージは複数のレイヤーから構成されている。レイヤーとは、イメージ内の変更や操作を表現するためのスナップショット。Dockerイメージ構築の際、ファイルの追加やコマンドの実行といった操作は新しいレイヤーとして保存される。各レイヤーは個別にキャッシュされるため、同じ操作を行う場合はキャッシュから再利用される。結果、重複する操作が最小限に抑えられ、ビルドの高速化につながる。
  • docker history コマンドでイメージの履歴情報を確認可能。各レイヤーが作成された際に実行されたコマンドを確認可能。
  • DockerのRUNコマンドはベースイメージに対して操作を行う。RUNコマンドは新しいレイヤーを作成し、そのレイヤー上でコマンドを実行する。ベースイメージは変更されず、新しいレイヤーに変更内容が追加される。
  • RUNコマンドではShell形式での記述とExec形式での記述が可能だが、Exec形式を利用するとシェルを介さずに実行できるので余分なプロセスを発生させずに済む。
# Dockerfile

# Shell形式
RUN echo hello
# Exec形式
RUN ["echo","hello"]
  • RUNはイメージを作成するために実行するコマンド。イメージから生成したコンテナでコマンドを実行するには、CMDを利用する。

参考

プログラマのためのDocker教科書 インフラの基礎知識&コードによる環境構築の自動化 電子書籍(WINGSプロジェクト 阿佐 志保 山田 祥寛)|翔泳社の本