Think about that you just’ve simply completed constructing an software in Phoenix, and now, you’re able to share it with the remainder of the world. You could be questioning how precisely to navigate the discharge atmosphere and the place to launch your software.
Put merely, you may launch your challenge all over the place through the use of Docker. Elixir requires some runtime dependencies, primarily Erlang, in an effort to begin up the BEAM. Within the Deploying with Releases part of the Phoenix launch docs, there is a wonderful Dockerfile obtainable that serves as a fantastic place to begin. On this tutorial, I’ll dissect this Dockerfile and clarify what every step does, enabling you to choose and select what components of it you want and perhaps what components it’s essential to change to serve your individual challenge’s wants. Let’s get began!
Getting began
Simply as a teaser, I’ll embrace Node.js and npm on this publish, which aren’t included within the official Dockerfile within the docs:
ARG ELIXIR_VERSION=1.14.0 ARG OTP_VERSION=25.0.3 ARG DEBIAN_VERSION=bullseye-20210902-slim ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
Within the code above, we outline every step individually, which can make extra sense afterward within the tutorial. For now, we outline which Elixir model we wish to compile with, what Erlang OTP model we would like, and what Linux picture we wish to function our workhorse.
The construct step
We’ll begin off through the use of a builder picture:
FROM ${BUILDER_IMAGE} as builder # set up construct dependencies RUN apt-get replace -y && apt-get set up -y build-essential git nodejs npm curl && apt-get clear && rm -f /var/lib/apt/lists/*_* RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && apt-get set up -y nodejs # put together construct dir WORKDIR /app
The code above contains a lot of the dependencies that we’ll want, like Node.js, npm, and cURL. However, in case you want extra ones, you may add them right here. Take into account that not each picture might want to add Node.js, so you may take away this step if you wish to.
That takes care of the setup. From right here on out, it’s all about our software:
# set up hex + rebar RUN combine native.hex --force && combine native.rebar --force # set construct ENV ENV MIX_ENV="prod" # set up combine dependencies COPY combine.exs combine.lock ./ RUN combine deps.get --only $MIX_ENV RUN mkdir config # copy compile-time config recordsdata earlier than we compile dependencies # to make sure any related config change will set off the dependencies # to be re-compiled. COPY config/config.exs config/${MIX_ENV}.exs config/ RUN combine deps.compile COPY priv priv COPY lib lib COPY belongings belongings WORKDIR belongings RUN node --version RUN npm i -g yarn; yarn set model secure RUN yarn set up WORKDIR ../ # compile belongings RUN combine belongings.deploy # Compile the discharge RUN combine compile
First, we use combine to put in Rebar v3 and Hex. Rebar handles native Erlang libraries, whereas combine will get our Elixir dependencies; you may examine it with what npm is for Node.js. Then, we copy over our mixfile, which denotes our dependencies for the challenge, in addition to the lockfile and configs from our supply code.
We then fetch all of the dependencies and compile them. Notice that this solely compiles the dependencies and never our challenge recordsdata; these are two separate steps. Lastly, we copy over our challenge recordsdata:
priv
: Migrations and static recordsdatalib
: Our supply codebelongings
: Our JavaScript and CSS code
The following 5 steps are optionally available. For those who’re utilizing Node.js and npm, change your workdir
to the belongings
folder, set up the dependencies utilizing both Yarn or npm, after which change the workdir
again to src/
.
At this level, we are able to deploy our belongings, which is a particular step that makes all our JavaScript and CSS recordsdata prepared for deployment.
Subsequent, we compile the remainder of our Elixir supply code, making each file in our challenge prepared for the ultimate construct step, the discharge construct:
# Modifications to config/runtime.exs do not require recompiling the code COPY config/runtime.exs config/ COPY rel rel RUN combine launch
Discover how we copy over the runtime config after the compilation step. This serves as a superb reminder that every one the configuration in each different config file is compiled into the discharge and subsequently not changeable at this level. However, the config in our runtime config, because the identify suggests, is learn at runtime.
RUN combine launch
will construct a launch file that consists of all the pieces we have to run our software.
The runtime step
# begin a brand new construct stage in order that the ultimate picture will solely comprise # the compiled launch and different runtime requirements FROM ${RUNNER_IMAGE} RUN apt-get replace -y && apt-get set up -y libstdc++6 openssl libncurses5 locales && apt-get clear && rm -f /var/lib/apt/lists/*_* # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /and so forth/locale.gen && locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 WORKDIR "/app" RUN chown no one /app # set runner ENV ENV MIX_ENV="prod" # Solely copy the ultimate launch from the construct stage COPY --from=builder --chown=no one:root /app/_build/${MIX_ENV}/rel/myapp ./ USER no one CMD ["/app/bin/server"]
Once more, the code above is lifted from the official Phoenix docs, however as soon as once more, I’ll make clear the place the feedback fall brief.
Right here, we reference our earlier ARGS
, however this time, we solely take the Linux picture. This in itself makes our runtime Docker picture exceptionally smaller.
One other profit from our earlier setup the place we put in node_modules
, combine packages, and so forth, is that to run our Elixir app, we solely want the binary created from our combine launch
step on the finish of the construct half, lowering our construct picture measurement exceptionally.
We permit everybody to the touch our app listing, change our consumer to a severely restricted consumer, after which run the app.
Conclusion
Though the steps on this article are lengthy, mainly, it boils right down to the next single command which you could run:
> combine phx.gen.launch --docker
The code above will generate a Dockerfile much like the one we coated on this article, however with some variations. The usual Phoenix challenge doesn’t use Node.js, and subsequently, it doesn’t embrace the Node.js steps I’ve included on this Dockerfile.
This Dockerfile serves as a place to begin to deploy your Phoenix software, and on this article, I’ve proven the way to change it to suit your wants. On this case, we included the npm and Node.js steps. From right here, all it’s essential to do is mess around and work out what specifics you want.
The cool factor about having a separate builder and runtime picture is that there isn’t a actual price to together with an excessive amount of information within the builder picture. Sure, it’ll gradual your construct down, however most of these items might be cached in your pipeline, and regionally, it’s robotically cached. It doesn’t matter what, your runtime picture will likely be small and fast to launch as a result of it’s a barebones Linux distribution.
I hope you loved this text, and be sure you depart a remark when you have any questions.
LogRocket: Full visibility into your internet and cell apps
LogRocket is a frontend software monitoring resolution that permits you to replay issues as in the event that they occurred in your individual browser. As a substitute of guessing why errors occur, or asking customers for screenshots and log dumps, LogRocket helps you to replay the session to shortly perceive what went improper. It really works completely with any app, no matter framework, and has plugins to log extra context from Redux, Vuex, and @ngrx/retailer.
Along with logging Redux actions and state, LogRocket information console logs, JavaScript errors, stacktraces, community requests/responses with headers + our bodies, browser metadata, and customized logs. It additionally devices the DOM to report the HTML and CSS on the web page, recreating pixel-perfect movies of even probably the most complicated single-page and cell apps.