Run an Elixir app
In this guide we create and deploy a simple Elixir-based HTTP web server. To run this example, follow these steps:
-
Install the
kraft
CLI tool and a container runtime engine, e.g. Docker. -
Clone the
examples
repository andcd
into theexamples/http-elixir1.16/
directory:
git clone https://github.com/kraftcloud/examplescd examples/http-elixir1.16/
Make sure to log into Unikraft Cloud by setting your token and a metro close to you.
We use fra0
(Frankfurt, 🇩🇪) in this guide:
# Set Unikraft Cloud access tokenexport UKC_TOKEN=token# Set metro to Frankfurt, DEexport UKC_METRO=fra0
When done, invoke the following command to deploy this application on Unikraft Cloud:
kraft cloud deploy -p 443:3000 -M 1024 .
The output shows the instance URL and other details:
[●] Deployed successfully! │ ├────────── name: elixir-qo9k3 ├────────── uuid: e5fbf089-b000-4b2d-a827-44a1f5d28f24 ├───────── state: running ├──────── domain: https://small-water-tl8lr8am.dal0.kraft.host ├───────── image: sha256:67f5df003758a1180932e931727f8cb7006bbbf6fdd84058e27fe05e4829bba0 ├──────── memory: 1024 MiB ├─────── service: small-water-tl8lr8am ├── private fqdn: elixir-qo9k3.internal ├──── private ip: 172.16.3.4 └────────── args: /usr/bin/wrapper.sh /usr/local/bin/mix run --no-halt
In this case, the instance name is elixir-qo9k3
and the URL is https://small-water-tl8lr8am.dal0.kraft.host
.
They are different for each run.
Use curl
to query the Unikraft Cloud instance of the Elixir-based HTTP web server:
curl https://small-water-tl8lr8am.dal0.kraft.host
Hello, World!
At any point in time, you can list information about the instance:
kraft cloud instance list
NAME FQDN STATE STATUS IMAGE MEMORY ARGS BOOT TIMEelixir-qo9k3 small-water-tl8lr8am.dal0.kraft.host running since 9mins sha256:67f5df0... 1.0 GiB /usr/bin/wrapper.sh /usr/local/bin/mix r... 437.43 ms
When done, you can remove the instance:
kraft cloud instance remove elixir-qo9k3
Customize your Application
To customize the application, update the files in the repository, listed below:
lib/
,mix.esx
: the actual Elixir HTTP serverKraftfile
: the Unikraft Cloud specificationDockerfile
: the Docker-specified application filesystem
defmodule Server do@moduledoc """A Plug that always responds with a string"""import Plug.Conn
def init(options) dooptionsend
@doc """Simple route that returns a string"""@spec call(Plug.Conn.t(), any) :: Plug.Conn.t()def call(conn, _opts) doconn|> put_resp_content_type("text/plain")|> send_resp(200, "Hello, World!\n")endend
defmodule Server.Application do# See https://hexdocs.pm/elixir/Application.html# for more information on OTP Applications@moduledoc false
use Application
@impl truedef start(_type, _args) dochildren = [ # Starts a worker by calling: Server.Worker.start_link(arg) # {Server.Worker, arg} {Plug.Cowboy, scheme: :http, plug: Server, options: [port: 3000]}]
# See https://hexdocs.pm/elixir/Supervisor.html# for other strategies and supported optionsopts = [strategy: :one_for_one, name: Server.Supervisor]Supervisor.start_link(children, opts)endend
defmodule Server.MixProject douse Mix.Project
def project do[ app: :server, version: "0.1.0", elixir: "~> 1.14", start_permanent: Mix.env() == :prod, deps: deps()]end
# Run "mix help compile.app" to learn about applications.def application do[ extra_applications: [:logger], mod: {Server.Application, []}]end
# Run "mix help deps" to learn about dependencies.defp deps do[ # {:dep_from_hexpm, "~> 0.3.0"}, # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} {:plug_cowboy, "~> 2.0"}]endend
spec: v0.6
name: elixir
runtime: base-compat:latest
rootfs: ./Dockerfile
cmd: ["/usr/bin/wrapper.sh", "/usr/local/bin/mix", "run", "--no-halt"]
FROM --platform=$BUILDPLATFORM elixir:1.16.2-slim as build
WORKDIR /src
COPY . .
RUN mix deps.get
RUN MIX_TARGET=$TARGETARCH mix compile
FROM alpine:3 AS sys
RUN set -xe; \mkdir -p /target/etc; \mkdir -p /blank; \apk --no-cache add \ ca-certificates \ tzdata \; \update-ca-certificates; \ln -sf /usr/share/zoneinfo/Etc/UTC /target/etc/localtime; \echo "Etc/UTC" > /target/etc/timezone;
FROM --platform=$TARGETPLATFORM elixir:1.16.2-slim as runtime
FROM scratch
COPY --from=sys /target/etc /etcCOPY --from=sys /usr/share/zoneinfo/UTC /usr/share/zoneinfo/UTCCOPY --from=sys /usr/share/zoneinfo/Etc/UTC /usr/share/zoneinfo/Etc/UTCCOPY --from=sys /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crtCOPY --from=sys /blank /tmp
COPY --from=runtime /lib/x86_64-linux-gnu/libc.so.6 \ /lib/x86_64-linux-gnu/libgcc_s.so.1 \ /lib/x86_64-linux-gnu/libm.so.6 \ /lib/x86_64-linux-gnu/libsctp.so.1 \ /lib/x86_64-linux-gnu/libstdc++.so.6 \ /lib/x86_64-linux-gnu/libtinfo.so.6 \ /lib/x86_64-linux-gnu/libcrypto.so.3 \ /lib/x86_64-linux-gnu/libselinux.so.1 \ /lib/x86_64-linux-gnu/libc.so.6 \ /lib/x86_64-linux-gnu/libpcre2-8.so.0 \ /lib/x86_64-linux-gnu/
COPY --from=runtime /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
COPY --from=runtime /usr/local/lib/erlang /usr/local/lib/erlangCOPY --from=runtime /usr/local/lib/elixir /usr/local/lib/elixir
# Erlang and Elixir-related executablesCOPY --from=runtime /usr/local/bin /usr/local/bin
COPY --from=runtime /usr/lib/locale /usr/lib/locale
COPY --from=runtime /usr/bin/dirname \ /usr/bin/basename \ /usr/bin/readlink \ /usr/bin/env \ /usr/bin/
COPY --from=runtime /bin/rm \ /bin/mknod \ /bin/bash \ /bin/sh \ /bin/
COPY --from=build /root /root
COPY --from=build /src/deps /src/depsCOPY --from=build /src/_build /src/_buildCOPY --from=build /src/lib /src/libCOPY --from=build /src/mix.exs /src/mix.exsCOPY --from=build /src/mix.lock /src/mix.lock
COPY ./wrapper.sh /usr/bin/wrapper.sh
The following options are available for customizing the application:
-
If only updating the implementation in the
lib/server.ex
orlib/server/application.ex
source code files, no other changes are required. If new source files are added in thelib/
directory, no other change is required. -
If new files are added, these have to be copied in the application filesystem, using the
COPY
command in theDockerfile
. -
More extensive changes may require expanding the
Dockerfile
with additionalDockerfile
commands.
The current source code files and configuration file (mix.exs
) are generated using:
mix new --app server . --sup
Use a similar command to create a new application. Then update it and deploy it on Unikraft Cloud using the above instructions.
Learn More
Use the --help
option for detailed information on using Unikraft Cloud:
kraft cloud --help
Or visit the CLI Reference.