Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Elixir on Containers
Search
さっちゃん
May 19, 2019
Programming
1.1k
1
Share
Elixir on Containers
Know-how that ops Elixir on Docker containers.
さっちゃん
May 19, 2019
More Decks by さっちゃん
See All by さっちゃん
火星曆
ne_sachirou
0
22
みんなのオブザーバビリティプラットフォームを作ってるんだがパフォーマンスがやばい #mackerelio #srenext
ne_sachirou
0
1.7k
作ってよかったgraceful shutdownライブラリ #kyotogo
ne_sachirou
0
1.4k
path 依存型って何?
ne_sachirou
0
830
野生の onbording と onbording 設計 #kyototechtalk
ne_sachirou
0
730
メトリックはいかにして見え續ける樣になったか #devio2022
ne_sachirou
0
130
名實一致
ne_sachirou
0
740
まかれるあなとみあ ―Mackerel のしくみを理解する 30 分― @ Hatena Engineer Seminar #16
ne_sachirou
0
3.3k
tacit programming : Point-free, Concatenatives & J
ne_sachirou
0
1.1k
Other Decks in Programming
See All in Programming
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
180
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
450
TypeScriptだけでAIエージェントを作る フロント・エージェント・インフラのフルスタック実践
har1101
6
1.3k
Copilot CLI の継戦能力を高める コンテキスト管理
nozomutu
1
1.2k
CSC307 Lecture 17
javiergs
PRO
0
310
Modding RubyKaigi for Myself
yui_knk
0
870
Oxcを導入して開発体験が向上した話
yug1224
4
280
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
530
Lessons from Spec-Driven Development
simas
PRO
0
130
柔軟なPDFレイアウトエディタを支える型システム設計 — Discriminated UnionとConditional Typeの実践
minako__ph
4
1.3k
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
3
850
次世代リンターで探る、tsgo 時代における型認識カスタムルールの現実解
ytakahashii
3
1.4k
Featured
See All Featured
Information Architects: The Missing Link in Design Systems
soysaucechin
0
960
New Earth Scene 8
popppiees
3
2.3k
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
220
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.1k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
74k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
200
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
150
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
62
54k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
200
Marketing to machines
jonoalderson
1
5.3k
Side Projects
sachag
455
43k
AI: The stuff that nobody shows you
jnunemaker
PRO
8
680
Transcript
Elixir on Containers
.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)
Container is good, because: It gives an abstract of processes
with environments. It's easy to deploy.
I'm using container for Elixir server @ dev, test &
prod. A little bit stateful WebSocket servers. Umbrella Related tools: Distillery, Dialyzer, docker‑compose, Kubernetes.
Containers for local dev
Why use containers for local dev? Use the same env
between Alchemist team members. Use the same env between non‑Alchemist team members. (Rubyist, frontend enginier, etc.) Use the near env between dev, test & prod.
I maintain Docker images that fixes both Erlang & Elixir
ver.
Work with the team & CI (Continuous Integration).
My application have some umbrellas. apps/ app_a/ app_b/
Dockerfile (deps.compile & dialyzer ‑‑plt) FROM nesachirou/elixir:1.8_erl21 SHELL ["/bin/ash", "-ex",
"-o", "pipefail", "-c"] RUN apk add --no-cache -t .build-deps \ ~ \ git \ && rm -rf /var/cache/apk/* WORKDIR /var/www VOLUME /var/www COPY mix.exs mix.lock ./ COPY apps/app_a/mix.exs apps/app_a/ COPY apps/app_b/mix.exs apps/app_b/ RUN mix "do" deps.get, deps.compile \ && MIX_ENV="test" mix deps.compile \ && mix dialyzer --plt \ && mv _build deps /tmp RUN apk add --no-cache -t .runtime-deps \ inotify-tools \ rsync \ && rm -rf /var/cache/apk/* EXPOSE 4000 4001 CMD ["./entrypoint.sh"]
entrypoint.sh #!/bin/sh -eux # shellcheck shell=dash if test "$(stat /.dockerenv
> /dev/null || echo $?)" ; then : "Outside Docker" mix "do" deps.get, compile else : "Inside Docker" rsync -au /tmp/_build /tmp/deps . mix "do" deps.get, compile fi elixir --name
[email protected]
--cookie example -S mix phx.server
docker-compose.yml --- version: "3" services: example: image: example.docker.registry/example/example:latest depends_on: [example-src]
logging: options: max-size: "100m" max-file: "2" ports: - 4000:4000 - 4001:4001 volumes: - example-src:/var/www ~
docker-compose.override.yml --- version: "3" services: example: build: context: . dockerfile:
Dockerfiles/Dockerfile.dev docker-compose build --pull --force-rm docker-compose push
docker‑sync http://docker‑sync.io/ Docker (for MacOS) is too slow in it's
file IO between containers & the host. docker‑sync solves this, but troublesome. I do a little bit different way (unison + rsync).
docker-compose.yml ~ example-src: image: eugenmayer/unison:2.51.2.1 environment: APP_VOLUME: /app_sync HOST_VOLUME: /host_sync
TZ: Asia/Tokyo UNISON_ARGS: | -debug default -ignore 'Name .git/*' -ignore 'Name _build/*' \ -ignore 'Name deps/*' -prefer /host_sync -numericids -auto -batch UNISON_DEST: /app_sync UNISON_SRC: /host_sync UNISON_WATCH_ARGS: -repeat watch volumes: - ../example:/host_sync:cached - example-src:/app_sync volumes: example-src:
precopy_appsync #!/bin/bash -eux rsync -auv \ --delete \ --exclude='.git/*' --exclude='_build/*'
--exclude='deps/*' \ /host_sync/ /app_sync docker-compose -f example/docker-compose.yml stop example-src docker-compose -f example/docker-compose.yml run --rm --no-deps example-src \ /host_sync/tools/precopy_appsync docker-compose -f example/docker-compose.yml start example-src
Testing container image yamllint https://github.com/adrienverge/yamllint hadolint https://github.com/hadolint/hadolint container‑structure‑test https://github.com/GoogleContainerTools/container‑ structure‑test
Containers for prod
Work with CD (Continuous Delivery).
Umbrella apps/ app_a/ app_b/ common/
Distillery https://github.com/bitwalker/distillery {:distillery, "~> 2.0", runtime: false}, No hot code
swapping, RollingUpdate.
rel/config.exs ~ environment :prod do set(include_erts: true) set(include_src: false) set(cookie:
:" ~") set(vm_args: Path.join("rel", "vm.args.prod")) end release :app_a do set(version: "0.0.1") set(applications: [:app_a, :common, :runtime_tools]) set(commands: [app_terminate: "rel/commands/app_terminate.sh"]) set(overlay_vars: [ ~]) end
rel/commands/app_terminate.sh → ./bin/app_a app_terminate (PreStop hook) #!/bin/bash -eu COOKIE=$(awk '/-setcookie/{print$2}'
releases/0.0.1/vm.args) export COOKIE bin/app_a command Elixir.AppA.Command app_terminate AppA.Command defmodule AppA.Command do def app_terminate do :ok = do_rpc(:"
[email protected]
", :"
[email protected]
", AppA.AppTerminator, :request_terminate, [], 1_800_000) end defp do_rpc(target_node, node_name, module, fun, args, timeout) do Node.start(node_name) Node.set_cookie(String.to_atom(System.get_env("COOKIE"))) :rpc.call(target_node, module, fun, args, timeout) end end
Dockerfile for app_a (multi stage build) FROM nesachirou/elixir:1.8_erl21 as builder
SHELL ["/bin/ash", "-ex", "-o", "pipefail", "-c"] RUN apk add --no-cache -t .build-deps \ build-base \ ~ \ git ARG REVISION ENV MIX_ENV=prod WORKDIR /var/www COPY mix.exs mix.lock ./ COPY apps/app_a/mix.exs apps/app_a/ COPY apps/common/mix.exs apps/common/ RUN mix "do" deps.get --only prod, deps.compile COPY apps/app_a apps/app_a COPY apps/common apps/common COPY config config COPY rel rel # hadolint ignore=DL3003 RUN mix compile \ && mix release --verbose --name=app_a ~
Dockerfile for app_a (multi stage build) ~ FROM alpine:3.9 SHELL
["/bin/ash", "-ex", "-o", "pipefail", "-c"] RUN apk add --no-cache -t .runtime-deps \ bash \ inotify-tools \ openssl \ && rm -rf /var/cache/apk/* WORKDIR /var/www # hadolint ignore=DL3010 COPY --from=builder /var/www/_build/prod/rel/app_a/releases/0.0.1/app_a.tar.gz ./ RUN tar xzf app_a.tar.gz \ && rm -rf app_a.tar.gz EXPOSE 80 4369 CMD ["bin/app_a", "foreground"]
container-structured-test.yml --- schemaVersion: "2.0.0" commandTests: - name: Application meta data
command: bin/example args: [describe] expectedOutput: - example-0.0.1 - "Name:
[email protected]
" - name: libcrypto command: bin/example args: [eval, ":crypto.strong_rand_bytes(8)"] metadataTest: cmd: [bin/example, foreground] exposedPorts: ["80", "4369"] workdir: /var/www