go-sqlrow

この記事はGo2 Advent Calendar 2017 13日目の記事です。 昨日は@kami_zh さんの Goで標準出力をキャプチャするパッケージを書いた でした。 go-sqlrow Go言語で標準パッケージを使用してRDBMSからデータを取ってくるには、以下の様に書きます1。 1 2 3 4 5 6 7 8 9 type Person struct { ID string Name string } db, _ := sql.Open("dn", "dsn") row, _ := db.Query(`SELECT id, name FROM person where id='foo'`) var p Person row.Scan(&p.ID, &p.Name) SQL文を発行するまではいいのですが、最後の行、sql.Row#Scanがくせ者です。 上記の例のように、sql.row#Scanは可変長個のポインタを引数にとり、それらにそれぞれ値をセットします。この例では値の数が2つのため大きな問題ではありませんが、値の数が増えた場合などは非常に面倒です。また、テーブルの構造が変わった場合なども非常に面倒です。 この問題を解決するため、go-sqlrow という小さなパッケージを作りました2。 これは上記のrow.Scanを代わりにやってくれるパッケージです。 機能・使い方は簡単で、先ほどの例を次の様に書き換えます。 1 2 3 4 5 6 7 8 9 type Person struct { ID string Name string } db, _ := sql.Open("dn", "dsn") row, _ := db.Query(`SELECT id, name FROM person where id='foo'`) var p Person sqlrow.Bind(row, &p) 後は内部でrow.Scan相当の処理を行います。 unexportedなフィールドはencoding/json同様、sql.Rowとの対応がとれませんので、注意が必要です。 エラー処理やトランザクションなどは省略 ↩︎ godoc: https://godoc.org/github.com/nasa9084/go-sqlrow  ↩︎ ...

2017-12-13 · nasa9084

Parcel + Riot.js

この記事は Riot.js Advent Calendar 2017 13日目の記事です。 昨日は@supple さんによるRiot+ElectronでMarkdownエディタを作る でした。 tl;dr Parcel というJavaScriptのモジュールバンドラを触ってみた webpackなどと比べて設定ファイルなどもいらずとても簡単 ホットリロードな開発サーバを簡単に実行できる Riotと組み合わせるのもそれほど難しくない Parcel + Riot.js Parcel というJavaScriptのモジュールバンドラが話題なのでさわってみました。 国内で話題になっている元の記事は「webpack時代の終わりとparcel時代のはじまり 」。 React との組み合わせで記事を書かれています。 個人的にはRiot.js が好みなので、Riot.jsとの組み合わせで触ってみました。 尚、webpackは挫折したため比較できません。 Parcel/Riot.jsのインストール npmを使ってインストールします。 1 $ npm install -g parcel-bundler riot source code ディレクトリ構造 以下の様なディレクトリ構造だとします。 なお、練習用のため、動作確認に関係ない部分は適当に削っています。 src/ |- index.html |- index.js |- package.json |- app/ | |- App.tag index.html 1 2 3 4 5 6 7 8 <!doctype html> <html lang="ja"> <head></head> <body> <App></App> <script src="index.js"></script> </body> </html> index.js 1 2 3 4 import riot from 'riot' import './app/tags' riot.mount('App') App.tag 1 2 3 4 5 6 7 <App> <h1>Hello, parcel world!</h1> <script> import riot from 'riot' </script> </App> package.json package.jsonはnpm init -yで作成しました。 ...

2017-12-12 · nasa9084

kubesprayを使用してkubernetes clusterを構築する

注意: 情報が古くなっています。新しい情報にあわせて記事を書いた ので、そちらをご覧ください。 kubespray はproduction readyなkubernetes(k8s)クラスタを構成できるツールです。 Ansible をベースに作られているため、任意のサーバでk8sクラスタを構成できます。 今回は、3台のVMを用意してクラスタを構成してみます1。 検証環境 今回用意したVMは以下の構成です。 2Core 8GB RAM 80GB HDD CentOS 7 IPアドレスは以下の様になっているものとします。 192.168.1.11 192.168.1.12 192.168.1.13 また、kubesprayを実行するローカルの環境はmacOS Sierraです。 各ホストのrootユーザに対してSSH鍵は配置済み、firewalldは無効化されているとします。 requirements 実行する環境に、Ansible が必要なため、pipでインストールします。23 1 $ pip install ansible install kubespray-cli kubespray自体もpipでインストールします。 1 $ pip install kubespray prepare 設定ファイルを生成するため、kubespray prepareを使用します。 1 $ kubespray prepare --nodes node1[ansible_ssh_host=192.168.1.11] node2[ansible_ssh_host=192.168.1.12] node3[ansible_ssh_host=192.168.1.13] deploy 以下のコマンドでk8sクラスタをデプロイします。 1 $ kubespray deploy -u root -n flannel 今回はflannel ネットワークプラグインで構成しました。 kubesprayは、次のネットワークプラグインを使用してクラスタを構成することができます。 flannel 4 calico 5 canal contiv 6 weave 7 あとは構成が終了するのを待つだけです。 ...

2017-11-30 · nasa9084

GitLab Docker: initial runners registration token

GitLab はRuby on Railsで書かれたオープンソースのGitサーバアプリケーションです。おそらく、オープンソースのGitサーバとしては最もよく使われているものではないでしょうか。 GitLabは他のOSS Gitサーバアプリケーションと比べて、非常に多くの機能を持っています。 GitLab-CIもその一つで、GitLab上で自動テストを回すことができます。 この、GitLab-CIを使用するにはrunnerと呼ばれる、CI環境用のホストを追加する必要があります。 このとき、Registration Tokenという登録用トークンが必要なのですが、REST APIで取得することができません。そのため、Dockerを用いた自動構築時に少々困りました。 解法 GitLab omnibusの設定項目でRegistration Tokenの初期値を設定することができます。 docker runする際のオプションに、以下を追加します。 1 -e GITLAB_OMNIBUS_CONFIG="gitlab_rails['initial_shared_runners_registration_token'] = 'HOGEHOGETOKEN'" もし、ほかの理由ですでにGITLAB_OMNIBUS_CONFIGの指定がある場合、セミコロン区切りで複数の値を指定することができます。たとえば、初期パスワードを与えている場合は、以下の様にできます。 1 -e GITLAB_OMNIBUS_CONFIG="gitlab_rails['initial_root_password'] = 'FUGAFUGAPASSWORD'; gitlab_rails['initial_shared_runners_registration_token'] = 'HOGEHOGETOKEN'" ここで指定した値をrunnerの登録時に与えれば、OKです。 1 docker exec GITLAB_RUNNER_CONTAINER_NAME gitlab-runner register -n -r HOGEHOGETOKEN --run-untagged --executor docker --docker-image alpine:latest --url http://GITLAB_URL --docker-volumes /var/run/docker.sock:/var/run/docker.sock このとき、GITLAB_RUNNER_CONTAINER_NAMEとGITLAB_URLは適宜置き換えてください。

2017-11-22 · nasa9084

Application Specific Context

元ネタは@lestrrat さんの「Abusing type aliases to augment context.Context 」。 golangを用いてHTTPサーバを作る場合、ルーティングを定義するのに以下の様な関数を用います。 1 http.HandleFunc(path string, handler func(w http.ResponseWriter, r *http.Request) もちろん、http.Handleを用いる場合もありますし、gorilla/mux などのライブラリを用いることもあると思います。 ここで重要なのは、func(w http.ResponseWriter, r *http.Request)という引数の方です。 多くの場合、アプリケーションのハンドラ内ではデータベースなどの外部アプリケーション・ミドルウェアを用いることになります。 しかし、golangのHTTPアプリケーションでは、ハンドラ関数の形式がfunc (w http.ResponseWriter, r *http.Request)と決まっています。引数の追加はできないため、引数以外の方法でDB接続情報などを渡す必要があります。 これまで、golangでWebアプリケーション開発を行う場合によく用いられていたデータベースコネクションの保持方法は、dbパッケージを作成し、そこにパッケージ変数として持つ方法かと思います。が、グローバルな変数はできるだけ持ちたくない ですよね。 そこで、Go 1.8から追加されたcontext を使うことができます。http.Request にはcontext.Contextが入っていて、Request.Context() でget、Request.WithContext() でsetできます。 context.Contextに値を持たせる方法で最初に思いつくのはContext.WithValue() を用いる方法ですが、これは値を取得する度にtype assertionをする必要があり、あまりよくありません 。 これを解消するため、自分で型を定義するのがよいでしょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package context // internal context subpackage import ( "context" "errors" ) type withSomethingContext struct { context.Context something *Something } func WithSomething(ctx context.Context, something *Something) context.Context { return &withSomethingContext{ Context: ctx, something: something, } } func Something(ctx context.Context) (*Something, error) { if sctx, ok := ctx.(*withSomethingContext); ok { if sctx.something != nil { return sctx.something, nil } } return nil, errors.New(`no asscosiated something`) } このように定義をすることで、毎回type assertionをする必要もなくなり、すっきりします。 ...

2017-11-21 · nasa9084

GNU MOファイルの構造

GNU MOファイルの内部構造について、最小限ですが解説します。

2017-11-06 · nasa9084

Travis CIでdockerのバージョンを最新にする

Travis CIでDockerfileをテストする等、dockerを使用したい場合、以下の様に.travis.ymlに記述することでdockerを有効にすることできます。 1 2 3 4 sudo: required service: - docker が、その際のdockerのバージョンは17.03.11と、最新版ではありません。 特に問題なのが、multi-stage build は17.05からの機能であるということです。 Travis CIで使用できるdockerでは、multi-stage buildを使用したDockerfileはビルドすることができず、常にfailedとなってしまいます。 解決方法 Travis-CIでDockerのバージョンを上げるには、以下の記述を.travis.ymlに追加します。 1 2 3 4 5 6 7 8 sudo: required service: - docker before_install: - sudo apt-get update - sudo apt-get install -y -o Dpkg::Options::="--force-confnew" docker-ce dockerの再起動などの処理は必要ありません。 以上の記述により、Dockerのバージョンが最新版にアップデートされ、multi-stage buildも使用できるようになります。 2017年10月18日現在 ↩︎

2017-10-18 · nasa9084

Kolla-AnsibleでOpenStack Ocata環境を構築する

OpenStack Kollaを用いると、比較的簡単にOpenStack on Docker環境を構築することができます。 今回はKolla-Ansibleを使用してall-in-one構成で4.0.0(Ocata)環境を構築してみます。

2017-10-04 · nasa9084

Kolla-ansible precheckで発生するエラーの対処

「OpenStack Kolla(Ocata)環境の構築」を参考にOpenStack Kollaのセットアップを行っていたら、エラーが出ました。

2017-09-29 · nasa9084

Functional Option Pattern

Fuctional Option PatternはGo言語において構造体の初期化時にオプション引数を与えるためのデザインパターンで、元ネタはRob Pike氏のSelf-referential functions and the design of options 、Dave Cheney氏のFunctional options for frendly APIS です。 Go言語には他の言語でオプション引数やキーワード引数と呼ばれる、省略可能な引数が存在しません。 通常は大きな問題は無いのですが、しかし、構造体の初期化時には、省略可能引数がほしくなる場合もあります。 Dave Cheney氏の記事にもある例を見てみましょう。 例 1 2 3 4 5 6 7 8 9 10 11 12 13 type Server struct { listener net.Listener } func NewServer(addr string) (*Server, error) { l, err := net.Listen("tcp", addr) if err != nil { return nil, err } srv := Server{listener: l} go srv.run return &srv, nil } よくある構造体の初期化関数です。 初期化が上手くいけば、ポインタとnilを、上手くいかなければnilとエラーを返す形になっています。 ここで、Serverになにがしかの拡張を加えることを考えます。たとえばタイムアウトや、TLS対応等です。 しかしこれらは指定する必要が無い場合もあります。 Go言語を用いたアプローチですぐに思いつくのは、オプションの組み合わせの数だけ初期化関数を作成することですね。(たとえば、With...というサフィックスを使って) しかしこれは、オプションの数が増えると、作成しなければならない関数の数が膨大になっていきます。 保守の観点から見てもこれは余りうれしくありません。 Config構造体を用いる そこでよく用いられるのが、設定を保持する構造体を用いる方法です。 例としては、以下の様にします。 1 2 3 4 5 6 7 8 type Config struct { Timeout time.Duration Cert *tls.Cert } func NewServer(addr string, config Config) { // ... } これも良く用いられているパターンです。 しかし、オプションを一切与えない場合のパターンを考えてみましょう。 ...

2017-09-26 · nasa9084