Skip to main content

常にいまいち

[Go] interfaceを埋め込んでラッパーを作る

こんな感じでinterfaceを埋め込んだ構造体を用意するとラッパーが簡単に作れる。 サードパーティライブラリの構造体の一部機能だけ上書きしたい時とかに便利。 package main import "fmt" type St interface { FuncA(string) string FuncB(int) int } type st struct{} func (r st) FuncA(s string) string { return s } func (r st) FuncB(i int) int { return i } var _ St = (*st)(nil) type st2 struct { St } func (r st2) FuncA(s string) string { return "new" + r.St.FuncA(s) } var _ St = (*st2)(nil) func main() { var v St v = &st{} fmt.

[Kubernetes]HPA使用時のreplicasの設定

DeploymentとHorizontalPodAutoscaler(HPA)の組み合わせでハマった箇所があったため、検証結果と検証用の資料をまとめた。 検証環境 Kubernetes version: 1.14.10-gke.27 検証資料: https://github.com/ques0942/k8s-hpa-sample 結論 HPA使用時はDeploymentにreplicasを設定しないほうが良い replicasありのDeploymentに後からHPAを適用したい場合 replicas無しのDeploymentをapplyすると一時的にPodは1つになる kubectl apply edit-last-applied deployment ${target} でDeploymentからreplicasを削除できる HPAでスケールアウトした後HPAを削除してもPod数はそのまま 最後にapplyしたDeploymentがreplicasを持たない場合、kubectl editでreplicasを書き換えたとしてもその後replicas無しのDeploymentをapplyしてもPod数は1にならない 詳細は後述するがkubectl applyの差分計算ロジックによる挙動 説明 Deploymentに紐づくPodの数は replicas に設定された数字と等しくなるが replicas が未設定の場合は1になる。 一方でHorizontal Pod Autoscaler(HPA)を使用すると、Deploymentの replicas は負荷状況に合わせて自動で変更される。では以下のようなユースケースの場合どのような挙動となるだろうか? 手順 replicas = 3としてDeploymentを適用する HPAを有効化する HPAでreplicasが10に増加した 1で適用したDeploymentを修正して適用したが、その時Deploymentのreplicasは3のままだった 問題 この手順を踏むと4の実施後にreplicasは3に戻ってしまう。 規模が大きくなってくるとデプロイ時にscale inすることになるため望ましくない挙動だろう。 対策 最後にapplyされたDeploymentを開いてreplicasを削除する kubectl apply edit-last-applied deployment ${target} を使う 以降applyするDeploymentにはreplicasを含めない 単純にreplicasを含まないDeploymentをapplyすると、一時的にPod数は1になるため注意。

Sliceを更に小さいSliceに分割して処理するサンプル

確認した環境 go1.16.3 使いみち バッチジョブなどの負荷を下げるために小規模のバッチに変換するようなときに使う。 コード片 package main import ( "fmt" "strings" ) func main() { ar := make([]string, 1000) for i := range ar { ar[i] = fmt.Sprint(i) } batchSize := 30 for i := 0; i < len(ar); i += batchSize { end := i + batchSize if len(ar) < end { end = len(ar) } batch := ar[i:end] fmt.Println(strings.Join(batch, ",")) } } refs: https://play.golang.org/p/gKaNr3KFHae

[Golang] deferでerrorを参照しようとしてハマった

概要

関数が返したerrorをdeferを使ってキャプチャしようとしたらハマったのでメモ。

起こったこと

関数でエラーが発生したらそれをログに残そうとしていたとき、以下のようなコードを書いてしまった。

func Execute() error {
	var err error
	defer func() { SendErrIfExists(err) }()

	err = DoSomething()
	if !errors.Is(err, ErrCanIgnore) {
		return err
	}

	return nil // ここに来たらSendErrIfExistsの引数はnilになって欲しい
}

このコードでDoSomethingがErrCanIgnoreを返すとエラーログにはしっかりとErrCanIgnoreが記録されてしまった。 原因は以下の2点。

  • deferで実行される関数がerr変数を含むクロージャとなっている
  • クロージャが参照しているerr変数に入った値がErrCanIgnoreのまま

[BigQuery] 抽出対象から一部のカラムを除く

select * from `dataset`; みたいなクエリを実行する時に select * except(`column1`) from `dataset`; とするとcolumn1が抽出結果から除外される。 JOINした際に同名カラムを除外するときなどに役に立つ。 参照 https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax?hl=ja#except

Kubernetesのenvは後勝ち

例えば以下のようにconfigmapとenvを併用するケース。 envFrom: - configMapRef: name: test-config env: -name: TEST value: "OVERRIDE" この順で書くとtest-configに TEST: DEFAULT などと定義されていてもTEST: OVERRIDE となる。 逆順で書けばtest-configに定義された値が優先される。 基本的には同一キーを定義しないほうが混乱が少なくてよいが、覚えておくと緊急時に一時的に上書きして対処できたりする。 参考 https://stackoverflow.com/questions/54398272/override-env-values-defined-in-container-spec

Go関連のTips

全部go1.14.3で検証したもの。 部分文字列の切り出し stringsパッケージにも部分文字列の切り出しを行うメソッドはないので、slice操作と同じようにして行う。 このとき注意がいるのが、マルチバイト文字の取り扱い。 単純に以下のようにすると3文字分ではなく3バイト分になる。 s := "あいうえお" fmt.Println(s[:3]) https://play.golang.org/p/ZHXH9FEneRJ 3文字分取り出したい場合は rune を使用する。 s := "あいうえお" fmt.Println(string([]rune(s)[:3])) https://play.golang.org/p/U1rbOpQ8H3c 参考 https://qiita.com/seihmd/items/4a878e7fa340d7963fee nilへの型アサーション 型付きnilなら型アサーションができる。 if _, ok := (interface{})(nil).(int); !ok { fmt.Println("no") // これが表示される } そのため、nilが返ってくる可能性のある関数の返り値に直接型アサーションを実行できる。 例えばこんな感じ。 if _, ok := New().(MyInterface); !ok { fmt.Println("nil") } https://play.golang.org/p/ExqB3G-1rN_-

GCSへのアクセス制御(特定ドメインのアカウントだけにアクセスを許可する)

やりたいこと XXX@gmail.comだけにアクセス許可 みたいな感じで特定のドメインのアカウントだけに限定して静的サイトを公開したい。 方法 consoleから変更する場合 GCSのブラウザを開く 対象のBucketの バケットオーバーフローメニュー(右端の縦に...が並んでいるボタン) をクリックする バケットの権限を編集 を選ぶ メンバーを追加 を選ぶ 新しいメンバーのフォームに許可したいドメイン(gmail.com など)を入力 適切なロールを選択して保存する。 問題 この方法でファイルを提供することはできるが、ファイルをディレクトリまるごとアップして許可した人だけにサイト公開しようとすると1点問題が発生した。 ファイルをホストするドメインがファイルごとに異なっているので相対パスを指定しても他のファイルを参照することができなかった。 GCSのブラウザで確認できる Link URL はhttps://storage.cloud.google.com/<bucket>/<file_name> となっているが、これにアクセスすると実際にファイルを配信している別のURLにリダイレクトされる。 このときリダイレクト先のURLのドメインが必ずしも同じドメインにならないようなので、そのまま単純に相対パスの状態でhtml/js/css/imgなどをアップするとリンク先が参照できなくて破綻する。 どうするかというと単純な話でhrefなどの参照先を絶対パスで指定すれば良い。 今回アップしようとしたファイル群は create-react-app で作成したので、.env ファイルに PUBLIC_URL=https://storage.cloud.google.com/<bucket>/<必要ならディレクトリ と記述して解決できた。 参考 https://cloud.google.com/storage/docs/access-control/using-iam-permissions?hl=ja#conditions-add https://stackoverflow.com/questions/52761957/attaching-absolute-path-to-css-js-files-while-building-the-react-app/52840500#52840500