minikubeを触った
ふとkubernetesを触ってみようと思い、ローカルで試すにはminikubeがよいということで試してみた。一通りチュートリアルをやってわかった気になったので、ちょっとした構成をつくってみたのがこちら。
docker hubに上げてないイメージを使うために
$ minikube start $ eval $(minikube docker-env)
とかしないといけないはず。これをした上で、
$ ./build.sh
とすると、docker build
やらDeploymentの作成が行われ、以下が2組立ち上がる。
- 80番を3000番にリバースプロキシするnginx
- 今の時刻を文字で返すWebアプリ
$ ./build.sh Sending build context to Docker daemon 5.718MB Step 1 : FROM golang:alpine ---> c82f63bb2928 Step 2 : ADD . /tmp ---> Using cache ---> be2da95d39d6 Step 3 : WORKDIR /tmp ---> Using cache ---> 153c17f1ff46 Step 4 : RUN go build -o /opt/app app.go ---> Using cache ---> d70e89cd9650 Step 5 : ENTRYPOINT /opt/app ---> Using cache ---> f48256763296 Successfully built f48256763296 Sending build context to Docker daemon 3.584kB Step 1 : FROM nginx:latest ---> 5766334bdaa0 Step 2 : COPY ./nginx.conf /etc/nginx/ ---> Using cache ---> d71e8a6ed75d Successfully built d71e8a6ed75d deployment "current-time" created service "current-time" exposed open 192.168.99.100:31744
最後に出力されているURLへ行くと、"2017-04-23 08:11:50.512403779 +0000 UTC"
という感じが見えて、動いていることが確認できる。
asdf-nodejsでgpgのエラー
最近macをセットアップする機会があったので、各言語のバージョン管理にasdfというやつを使い始めました。以前も一度試したのですが、なんだったか途中でコケてよくわからんから、まぁanyenvでいいか、となっていたので再挑戦。今度はそれなりにサクッと行きそうですが、1ヶ所つまずいたとこがあったので書いておきます。
asdf-nodejs
asdf自体のインストールはREADMEに従って行いました。まずはnodeでも入れるか、と思ってasdf-nodejsを入れたところ、インストール手順に
# Imports Node.js release team's OpenPGP keys to main keyring bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring
というものがありました。リリースチームの鍵を入れろよ、という話ですが、そのまま素直に打ったら「鍵サーバからの受信に失敗しました: no route to host」なんていうエラーが。import-release-team-keyring
の中身は
gpg --keyserver pool.sks-keyservers.net --recv-keys 94AE3...
というコマンドが列挙してあるだけで、サーバに辿り着けていないのかなと思うもping
は通る。ポートとかその辺かなーと思って調べると、どうやら
hkp://p80.pool.sks-keyservers.net:80
に別の口が開いているようなので、import-release-team-keyring
の中のpool.sks-keyservers.net
を置換して何とか鍵が入りました。署名とかに関することでエラーとか言われると不穏ですが、とりあえずこれで。
Phoenix v1.3からのディレクトリ構成をもう一度調べる
はいこんにちは。
Phoenix v1.3.0-rc.0がリリースされました。前リリースからの大きな変更として、Phoenixプロジェクトのディレクトリ構成がガラッと変わります。新たな構成に対応したジェネレータは、phoenix.*
ではなくphx.*
というタスクになっています。ついで感がありますが、phoenix.server
やphoenix.routes
もdeprecatedになり、phx.server
、phx.routes
になっていくようです。
以前v1.3以降でどんな構成になるのか調べたのですが、改めて調べておきましょう。
phx.new
まずはv1.2以前のphoenix.new
と、v1.3から入るphx.new
でつくられるプロジェクト構成を比較してみます。Phoenixのリポジトリをcloneして、installer
ディレクトリの中で以下のコマンドを発行。Phoenixのリビジョンは1.3.0-rc.0
タグのついた4d608bf
です。
$ mix phoenix.new app_with_phoenix_new $ mix phx.new app_with_phx_new --dev
phoenix.new
に--dev
つけたら--dev projects must be generated inside Phoenix directory
と怒られたのですが、ディレクトリ構成が見たいだけなので--dev
無しで。つくられたディレクトリをtree
で見るとこんな形式。一部省略してあります。
app_with_phoenix_new ├── README.md ├── config ├── lib │ ├── app_with_phoenix_new │ │ ├── endpoint.ex │ │ └── repo.ex │ └── app_with_phoenix_new.ex ├── mix.exs ├── priv │ ├── gettext │ └── repo ├── test │ ├── channels │ ├── controllers │ ├── models │ ├── support │ ├── test_helper.exs │ └── views └── web ├── channels ├── controllers ├── gettext.ex ├── models ├── router.ex ├── static ├── templates ├── views └── web.ex
app_with_phx_new ├── README.md ├── assets │ ├── brunch-config.js │ ├── css │ ├── js │ ├── package.json │ ├── static │ └── vendor ├── config ├── lib │ └── app_with_phx_new │ ├── application.ex │ ├── repo.ex │ └── web │ ├── channels │ ├── controllers │ ├── endpoint.ex │ ├── gettext.ex │ ├── router.ex │ ├── templates │ ├── views │ └── web.ex ├── mix.exs ├── priv │ ├── gettext │ └── repo └── test ├── support ├── test_helper.exs └── web ├── channels ├── controllers └── views
以前書いた
web
がlib
配下に入るmodel
という概念がなくなる
はそのままのようですが、加えて、これまでweb/static
配下にあったcss
、js
や、package.json
、brunch-config.js
がまるっとトップレベルのassets
に移っています。見慣れないapplication.ex
というファイルがありますが、これは上の例だとapp_with_phoenix_new.ex
に当たるもので、名称が変更されるようです。全体的にディレクトリ構成とモジュール名の対応関係がキチンとしていて、生成されたlib/app_with_phx_new/web/page_controller.ex
ではAppWithPhxNew.Web.PageController
モジュールが定義されていました。
defmodule AppWithPhxNew.Web.PageController do use AppWithPhxNew.Web, :controller def index(conn, _params) do render conn, "index.html" end end
ただ、よく見るとweb.ex
が入る場所が一段深くなっていて、lib/app_with_phx_new/web/web.ex
となっています。ここはモジュール名とファイル配置の対応が取れていませんが、Elixir ForumのJoséのコメントによると、意図したものであるようです。
phx.gen.json
次はphx.gen.json
を試してみます。まずはhelp
から。
$ mix help phx.gen.json mix phx.gen.json Generates controller, views, and context for an JSON resource. mix phx.gen.json Accounts User users name:string age:integer The first argument is the context name followed by the schema module and its plural name (used for resources and schema). The above generated resource will add the following files to lib/your_app: • a context module in accounts.ex, serving as the API boundary to the resource • a schema in accounts/user.ex, with an accounts_users table • a view in web/views/user_view.ex • a controller in web/controllers/user_controller.ex • default CRUD templates in web/templates/user As well as a migration file for the repository and test files for generated context and controller features. ## Schema table name By deault, the schema table name will be the plural name, namespaced by the context name. You can customize this value by providing the --table option to the generator. Read the documentation for phx.gen.schema for more information on attributes and supported options. Location: _build/dev/lib/phoenix/ebin
これまではmix phoenix.gen.json User users name:string age:integer
のように、スキーマのモジュール名とテーブル名、テーブル構造を引数に与えていましたが、Accounts
という第一引数が増えています。help
にある例をそのまま実行してみます。
$ mix phx.gen.json Accounts User users name:string age:integer * creating lib/app_with_phx_new/web/controllers/user_controller.ex * creating lib/app_with_phx_new/web/views/user_view.ex * creating test/web/controllers/user_controller_test.exs * creating lib/app_with_phx_new/web/views/changeset_view.ex * creating lib/app_with_phx_new/web/controllers/fallback_controller.ex * creating test/accounts_test.exs * creating lib/app_with_phx_new/accounts/user.ex * creating priv/repo/migrations/20170302235526_create_accounts_user.exs Add the resource to your api scope in lib/app_with_phx_new/web/router.ex: resources "/users", UserController, except: [:new, :edit] Remember to update your repository by running migrations: $ mix ecto.migrate
引数に与えたAccounts
がどこに効いているかというと、lib/app_with_phx_new/accounts/user.ex
のようにuser
のひとつ上の名前空間になっています。テーブル名も、特に指定しないとaccounts_users
となるようです。また、コンソールに出ていませんが、しれっとlib/app_with_phx_new/accounts/accounts.ex
も作られていました。このAccounts
モジュールはいわゆる「境界づけられたコンテキスト」のひとつで、他のモジュール、例えばUserController
は、User
モジュールに定義した関数を使ったり、Repo.all(User)
のようなことはせず、このAccounts
モジュール経由でユーザの操作を行うようにしましょうね、という意図があるようです。生成されたファイルの中を見ても、UserController
のindex
アクションでは、Accounts.list_users
を使ってユーザ一覧を得るようになっていました。User
モジュールはスキーマ定義があるだけでほぼ空っぽで、テストもUser
ではなくAccounts
モジュールのものが作られています。
ただ、生成されたAccounts
モジュールの中に以下の関数が定義されており、少々やりすぎではという印象でした。Accounts
モジュールが太っていきそうなので、自分ならこれは今まで通りUser
モジュールに移します。
def AppWithPhxNew.Accounts do ... defp user_changeset(%User{} = user, attrs) do user |> cast(attrs, [:name, :age]) |> validate_required([:name, :age]) end end
defmodule AppWithPhxNew.Accounts.User do use Ecto.Schema schema "accounts_users" do field :name, :string field :age, :integer timestamps() end # ここにchangeset/2を書きたい end
なお、lib/app_with_phx_new/web/controllers/fallback_controller.ex
という馴染みのないものがありますが、ちょっとここでは深掘りしません。
まとめ
ざっくりまとめると、
ということをフレームワークが緩く強制するということのようです。