Goを少し理解していく
プルリクを貰った
ありがたいことに、サンプル用プロジェクトなのにsecondrykeyさんにプルリクを貰った!
https://github.com/nyo3q1/golang_simple_api/pull/1
コードを見ると全体的にGoらしい書き方に修正してくれていた。
Goが分かっていないというのもあるけど。スクリプト言語に甘えていたツケが回ってきた感が凄いので、分からないなりに噛み砕いて理解していく。
構造体の配列はポインタで返す
DBから値を取得、それを元に構造体の配列を生成し返却する関数の戻り値はポインタで返す。
理由
大きな構造体や配列は値のまま返すとコピーの負荷が高いから
わかりやすく書いてある記事
https://qiita.com/knsh14/items/8b73b31822c109d4c497#receiver-type
コードはこんな感じ
type People struct { id int64 name string } type Peoples []People func GetPeoples() (*Peoples, error) { // 略 return &peoples, nil }
log.Fatal(funhttp.ListenAndServec())の動き
http.ListenAndServe は異常が起きた時のみ error を返すようになっている https://stackoverflow.com/questions/25920963/in-what-situation-will-http-listenandserve-return https://golang.org/doc/articles/wiki/#tmp_3
このQiitaが簡単にまとまっている
https://qiita.com/_kyamasan/items/f27978906c23fc3c49c3
ありがとう Shizuoka.go
このイベントに参加していなければプルリクは貰えませんでした。
本当に...ありがとう...
GoとRedisの環境をDocker Composeで構築する
とりあえず一番シンプルな構成はこんな感じかな?っていうのを作った https://github.com/nyo3q1/redis-de-go
Goのコードはこんな感じ
ホスト名 redis とポート番号書いて、パスワードとか設定するだけ。
func ExampleNewClient() { client := redis.NewClient(&redis.Options{ Addr: "redis:6379", Password: "", // no password set DB: 0, // use default DB }) pong, err := client.Ping().Result() fmt.Println(pong, err) // Output: PONG <nil> }
単純にredisに繋げに行くだけで、どの言語でも変わらないので書くことがない。
UptimeRobotはいいぞ
UptimeRobotはいいぞ
Webの死活監視は通常PingdomやらMackerelを使うと思います シンプルな監視だけで良ければ個人的にはUptimeRobotを推します。 https://uptimerobot.com/
問題
以前勤めていた会社ではこんな問題がありました
Web制作の部署のレンタルサーバで運用しているWordPressなサイトが落ちている事に気づけない。
選定基準
監視ツール系の導入にあたり以下の課題がありました。 - Web制作部には専任のエンジニアがいない - Zabbixの導入も検討したが操作があまりにも複雑 - Web制作の人だけで完結できるのを探していた - 監視対象のURLが生きているかどうか確認するだけのシンプルな監視ツールが欲しい - 運用管理コストが低いツールが良いのでSaaSが望ましい - 試験導入なのでコストが低ければ低いほど良い
そうすると候補に上がるのが、Pingdomになりますが若干お値段高めかつ多機能なので除外。
そして Pingdom alternative でググってみつけたのが UptimeRobot です
機能
機能としてはこんな感じ - 機能はシンプルでWebの死活監視 - グラフで日々のフェッチ速度が閲覧可能 - 異常時の通知先設定も複数設定可能
しかも監視対象50件までは無料で使え、有料版に移行すると、SSL証明書の有効期限の監視などWeb製作者に嬉しい機能付き。
締め
導入したところ意外と評判が良く、簡単に使いこなせているようでした。
(そのあとすぐ退職したので今どうなっているのか分かりませんが)
ちなみに、OSS版だとこれがなかなか良さそう。 https://github.com/hunterlong/statping/tree/master/handlers
Docker-composeで環境変数の値をファイルで管理する
DBの設定をアプリケーション側で利用したい時よくやるやつ
とりあえずどんなふうに書くのかというとこんな感じ
services: db: image: mysql:8.0 container_name: mysql_host environment: MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} MYSQL_DATABASE: ${DATABASE} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_USER_PASSWORD} TZ: '${TZ}' app: image: python container_name: app environment: MYSQL_DATABASE: ${DATABASE} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_USER_PASSWORD}
で、これをどのように変数を共通化しているかというと、docker-compose.yamlと同階層に .env ファイルを配置しこんな感じに書く。
B_ROOT_PASSWORD=root DATABASE=test_database DB_USER=docker DB_USER_PASSWORD=docker TZ=Asia/Tokyo
実務でこれ運用した事ないから知らないけど、何故これが便利かと想像すると。
env.get()
とかで値を取れば良いだけなので、アプリケーションにDBなどの情報を直接書かずにすむのが一番大きいのかな?
スケールのしやすさ、リポジトリに直接DBのパスワードとかあげなくてよくなったりとか...
一応このリポジトリで同じ事はやっている
GoでMySQLのデータを取得する
用意するテーブルはこんな感じ
id | name |
---|---|
1 | Taro |
1 | Jiro |
コード
一応ここに同じコードがある https://github.com/nyo3q1/golang_simple_api
package main import ( "log" "database/sql" _ "github.com/go-sql-driver/mysql" ) type People struct { id int64 name string } type Peoples []People func GetPeoples() Peoples{ db, err := sql.Open("mysql", "docker:docker@tcp(db)/test_database") if err != nil { log.Fatal("db error.") } rows, err := db.Query("select * from people") if err != nil { log.Fatal(err) } defer rows.Close() var peoples Peoples for rows.Next() { people := People{} if err := rows.Scan(&people.id, &people.name); err != nil { log.Fatal(err) } peoples = append(peoples, people) } defer db.Close() return peoples }
簡単な説明
説明する必要もないけど記事を書く上でコードだけというのも味気ないので...
この行で
sql.Open("mysql", "docker:docker@tcp(db)/test_database")
個人的に面白いなとおもったのが取得したデータを変数に格納するところ。
取得したカラムに沿っていかないとダメ。
取得するカラムを意識的に記述できて、レイテンシも向上しそうで好き。
rows.Scan(&people.id, &people.name)
ちなみにpeoplesをreturnするようにしているけど受け取り元ではこうやって書く
peoples := GetPeoples()
CircleCIのorbsを使うとメンテナンス性が簡単に向上する
CircleCIでGAEにデプロイする時に使ったので簡単に紹介
orbsの https://circleci.com/orbs/registry/orb/circleci/gcp-cli を利用する
まず、CircleCIの管理画面のBUILD SETTINGS > Environment Variables にこの3つを設定 - GCLOUD_SERVICE_KEY - GOOGLE_COMPUTE_ZONE - GOOGLE_PROJECT_ID
どのように設定するかは各自調べてください。
yamlは必要な箇所だけ見せるとこんな感じにシンプルにできる
version: 2.1 orbs: gcp-cli: circleci/gcp-cli@1.8.3 deploy: docker: - image: google/cloud-sdk:latest steps: - gcp-cli/initialize - run: name: Deploy to Google App Engine command: | gcloud --quiet app deploy app.yaml
PythonでGCSのオブジェクトをフォルダかどうか判定する
オブジェクトストレージってフォルダを作る概念はあるけど、実際はフォルダの概念は無いからAPIも用意されてないんですよね。
でもisdirって書きたい時あるよね? で、調べたら出てきて日本語の情報がなかったので書いておきます。
とりあえずこれがコード
def list_gcs_directories(bucket, prefix): # from https://github.com/GoogleCloudPlatform/google-cloud-python/issues/920 iterator = bucket.list_blobs(prefix=prefix, delimiter='/') prefixes = set() for page in iterator.pages: print page, page.prefixes prefixes.update(page.prefixes) return prefixes
そしてこれが該当のリンク
List subdirectories · Issue #920 · googleapis/google-cloud-python · GitHub
ただ自分が実装した時こっちのコードでしか動作しなかった、あまりオススメはできませんが貼っておきます。
List subdirectories · Issue #920 · googleapis/google-cloud-python · GitHub
ちなみに、luigiのGCSの実装を真似ればもっと綺麗にできます。
難点としてライブラリを google.cloud.storage から googleapiclient に変更しないといけない。