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
970
Elixir on Containers
Know-how that ops Elixir on Docker containers.
さっちゃん
May 19, 2019
Tweet
Share
More Decks by さっちゃん
See All by さっちゃん
みんなのオブザーバビリティプラットフォームを作ってるんだがパフォーマンスがやばい #mackerelio #srenext
ne_sachirou
0
1.3k
作ってよかったgraceful shutdownライブラリ #kyotogo
ne_sachirou
0
1.1k
path 依存型って何?
ne_sachirou
0
520
野生の onbording と onbording 設計 #kyototechtalk
ne_sachirou
0
590
メトリックはいかにして見え續ける樣になったか #devio2022
ne_sachirou
0
71
名實一致
ne_sachirou
0
620
まかれるあなとみあ ―Mackerel のしくみを理解する 30 分― @ Hatena Engineer Seminar #16
ne_sachirou
0
3k
tacit programming : Point-free, Concatenatives & J
ne_sachirou
0
870
Monitoring Containerized Elixir
ne_sachirou
1
930
Other Decks in Programming
See All in Programming
どうして手を動かすよりもチーム内のコードレビューを優先するべきなのか
okashoi
3
870
BEエンジニアがFEの業務をできるようになるまでにやったこと
yoshida_ryushin
0
200
ゼロからの、レトロゲームエンジンの作り方
tokujiros
3
1k
ドメインイベント増えすぎ問題
h0r15h0
2
560
PSR-15 はあなたのための ものではない? - phpcon2024
myamagishi
0
400
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
390
HTML/CSS超絶浅い説明
yuki0329
0
190
php-conference-japan-2024
tasuku43
0
430
Запуск 1С:УХ в крупном энтерпрайзе: мечта и реальность ПМа
lamodatech
0
950
「とりあえず動く」コードはよい、「読みやすい」コードはもっとよい / Code that 'just works' is good, but code that is 'readable' is even better.
mkmk884
6
1.4k
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
240
Fixstars高速化コンテスト2024準優勝解法
eijirou
0
190
Featured
See All Featured
Documentation Writing (for coders)
carmenintech
67
4.5k
Building Adaptive Systems
keathley
38
2.4k
Faster Mobile Websites
deanohume
305
30k
Building an army of robots
kneath
302
45k
Site-Speed That Sticks
csswizardry
2
270
A Philosophy of Restraint
colly
203
16k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
49
2.2k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
3
240
BBQ
matthewcrist
85
9.4k
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