From 3caf97ce9be8e7c220873506ad9c3cf227d76cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BCdiger=20Diedrich?= Date: Sun, 26 May 2024 17:34:34 +0200 Subject: [PATCH] Docker release --- .dockerignore | 45 +++++++++ Dockerfile | 91 ++++++++++++++++++ lib/homepage_web/controllers/page_html.ex | 2 +- make_release.sh | 2 +- ...go-6324e4f1039462023b0410cd1d5b7e83.svg.gz | Bin 1689 -> 1642 bytes priv/static/images/logo.svg.gz | Bin 1689 -> 1642 bytes ...ts-9e2c81b0855bbff2baa8371bc4a78186.txt.gz | Bin 164 -> 163 bytes priv/static/robots.txt.gz | Bin 164 -> 163 bytes 8 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..61a7393 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,45 @@ +# This file excludes paths from the Docker build context. +# +# By default, Docker's build context includes all files (and folders) in the +# current directory. Even if a file isn't copied into the container it is still sent to +# the Docker daemon. +# +# There are multiple reasons to exclude files from the build context: +# +# 1. Prevent nested folders from being copied into the container (ex: exclude +# /assets/node_modules when copying /assets) +# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc) +# 3. Avoid sending files containing sensitive information +# +# More information on using .dockerignore is available here: +# https://docs.docker.com/engine/reference/builder/#dockerignore-file + +.dockerignore + +# Ignore git, but keep git HEAD and refs to access current commit hash if needed: +# +# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat +# d0b8727759e1e0e7aa3d41707d12376e373d5ecc +.git +!.git/HEAD +!.git/refs + +# Common development/test artifacts +/cover/ +/doc/ +/test/ +/tmp/ +.elixir_ls + +# Mix artifacts +/_build/ +/deps/ +*.ez + +# Generated on crash by the VM +erl_crash.dump + +# Static artifacts - These should be fetched and built inside the Docker image +/assets/node_modules/ +/priv/static/assets/ +/priv/static/cache_manifest.json diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..07419b9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,91 @@ +# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian +# instead of Alpine to avoid DNS resolution issues in production. +# +# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu +# https://hub.docker.com/_/ubuntu?tab=tags +# +# This file is based on these images: +# +# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image +# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20240513-slim - for the release image +# - https://pkgs.org/ - resource for finding needed packages +# - Ex: hexpm/elixir:1.16.2-erlang-26.2.5-debian-bullseye-20240513-slim +# +ARG ELIXIR_VERSION=1.16.2 +ARG OTP_VERSION=26.2.5 +ARG DEBIAN_VERSION=bullseye-20240513-slim + +ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}" +ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}" + +FROM ${BUILDER_IMAGE} as builder + +# install build dependencies +RUN apt-get update -y && apt-get install -y build-essential git \ + && apt-get clean && rm -f /var/lib/apt/lists/*_* + +# prepare build dir +WORKDIR /app + +# install hex + rebar +RUN mix local.hex --force && \ + mix local.rebar --force + +# set build ENV +ENV MIX_ENV="prod" + +# install mix dependencies +COPY mix.exs mix.lock ./ +RUN mix deps.get --only $MIX_ENV +RUN mkdir config + +# copy compile-time config files before we compile dependencies +# to ensure any relevant config change will trigger the dependencies +# to be re-compiled. +COPY config/config.exs config/${MIX_ENV}.exs config/ +RUN mix deps.compile + +COPY priv priv + +COPY lib lib + +COPY assets assets + +# compile assets +RUN mix assets.deploy + +# Compile the release +RUN mix compile + +# Changes to config/runtime.exs don't require recompiling the code +COPY config/runtime.exs config/ + +COPY rel rel +RUN mix release + +# start a new build stage so that the final image will only contain +# the compiled release and other runtime necessities +FROM ${RUNNER_IMAGE} + +RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \ + && apt-get clean && rm -f /var/lib/apt/lists/*_* + +# Set the locale +RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/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 nobody /app + +# set runner ENV +ENV MIX_ENV="prod" + +# Only copy the final release from the build stage +COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/homepage ./ + +USER nobody + +CMD ["/app/bin/server"] diff --git a/lib/homepage_web/controllers/page_html.ex b/lib/homepage_web/controllers/page_html.ex index 99cf6ab..9f0563b 100644 --- a/lib/homepage_web/controllers/page_html.ex +++ b/lib/homepage_web/controllers/page_html.ex @@ -1,7 +1,7 @@ defmodule HomepageWeb.PageHTML do use HomepageWeb, :html import HomepageWeb.HelperComponents - + embed_templates "page_html/*" attr :url, :string, required: true diff --git a/make_release.sh b/make_release.sh index 552618f..3687589 100755 --- a/make_release.sh +++ b/make_release.sh @@ -7,6 +7,6 @@ export DATABASE_URL=ecto://postgres:postgres@localhost/homepage_dev mix deps.get --only prod MIX_ENV=prod mix assets.deploy MIX_ENV=prod mix compile -mix phx.gen.release +mix phx.gen.release --docker MIX_ENV=prod mix release diff --git a/priv/static/images/logo-6324e4f1039462023b0410cd1d5b7e83.svg.gz b/priv/static/images/logo-6324e4f1039462023b0410cd1d5b7e83.svg.gz index 9cd1598f1bcdea9e94546e93750fce802414616c..d33be3282a19bc4967e34bf5f3f3938832aeba1e 100644 GIT binary patch literal 1642 zcmV-w29^0AiwFP!0000015H=kZXLN1eD_xn$}`J-Z!)kABpd8oen4-+vDY>r*$dfg z@8<`_(Jlhvj7AiP(_LLv-RI4>A0Nk`Pmf=|y}kSN{rm6#eEs_8&!70|`1<_uwTZ~< zZ$CcXjUS&s{QURVKi}TTkkL9~-HqQqKR&*_yZ!O}{Nc;@U%ozmeZCtH&z~RWr_b-- zfB5qD?)&o}AMW108sp9H58pq%8e@$2Z||P0;H|?Q(LIrA6MCDDZ4+&K7JT<~=xk)q z!m>Tl?$h8F$lWs_p2K;a0gW{jd*_5~8xAiU3dtOS>|yXd6q!8~ZNsov3`geT291$$ z$zd?ze^dEj?;Zj57z-Xf9OZmUmrq2jk=VH=PfTuUosMM-UOwSk=+cSYj71|R)~d$| z3!ShPw`mY-lrx>}SfR6El4wr?z=X88#)oaqg6RmTjPmbol zs9{asjYda8gQ1-Oy_B>tCblH7H;d@Hhp@1*Z-^a32D%&~#WdZ95Qr$I5hGwsS|5pW_I-GlM6T3+i;@Me~q99XhzQpQOo5u-?Qj0D=x~V~16Do}r z#8Q})3r}*dQ}6pHHwd$DY>V53tR(Ek%fuF)3W=#Oqb64N)Po|WI`v4U;8Zcs?YyXA zhwD&VXQNJBn#l>{M!p~=c^BvOHd1k-7i#+?EY5f9in9@ir#$-LuBZuLJc7`A-f4FwlB&T1;>*_nN6)AI^?7FCU1{)nSdc=Jx)lFs}F|F`t2HWeuxaj zHgR)et$hGz;uFdmNX8@7jLSEL?O{;8JdUDWdPpSnDx-g*UsTx4Y6PNnsG*Owwg0QA z%os1f7={k-5rWlx#bzLf14YZFpLLQE`~GQeXiOJ))?%Kya@~CY% z_M&sjUZYTplF{uW;CYFo$3i#bCdnMO9f!in8X7er?!=0Dk*yA2IOevKIIEwQ;C&3n zXCp-Eq%4l>p%MAzEMpmV%tSa}pPf?$v62Fvnvi2WnSTFdO-c_a6Sq}P@kR$ZsA_uoHP-S6ulZ$;C(lYM#BVlgdLaa*S;!!h% zAXy+)=eLsrG{Oxra$lmk!ipE`*@TVk+I8%hRYYU$iA5>biJxRLx)JrKXsyW}K#Ueu zrb+r$aIf_J(_Ey+3{?VYv;rmc;5n`n%wjnxbt*I>75*E>n zObb7w!MSfCXma%WDnv5msso$RQ{%J zW!*nnpsj~C+Lct%bEuq=Z6~J|uRep_nn>@98ss{iE;wTm2^Bq~8po=DuXS2<*E*~^ z1J!BQ{Me?!=;;J$3~Lwk2y?NSwAKIL`k9!F2;V@?(i9$JcmuySd^we~<^f*Hkotq7sjyO^5*P*BL zu~D!g>*?2uq!P7Zd+LVUP3V*K8YK-bGII2yfTaHV%$JLwJ5rd#+=3{ha$+EZVv2ZZ z6s1#o^(}fnT|TJI=I8HzM)M569XAqsrLVJ|i*F&ae?Q9wu6oRCtG+DoKW2Xgn{3)= owi1o|yYqeF`i}9BU;h)oig4-myH{`cmE_(30Pj_5WV#Fh0Opr2`2YX_ literal 1689 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 literal 1689 zcmV;K24?vmiwFP!0000015KCBZX7odgztWe!R9;^n{56CmVv~9Z+QXTgtcr5kSs%% zEkAzh>yeE>*jWyjZ1zu8HTCw}kI&oBhx;$zE>E}5&tLz%xOjPaNiQ`$K7GC@Ip+(l zIBh@fZeIR={CRoGTi%9kK2O`HyZigg)A{?;)6JLX_mB6FPp9qr>F#>Jz5Dp_=F8>j z`RV)3>D`-cd;9hJ`BvZC_VM!cPA&!WVPj z)13W&PsKG`rk@p0E<;ucXKAl~=yIVc*hT^f$U1XuE_0u0b=S5wi=IBaPVd>YzuMA{ z;eBt~r!C!d%E+v)hQ&^bj{w4YPs^vqm7I7_tt)cxyjpKMLIqm!<~*}8fZheP3xB6;&9f;^e8yR;zNpc0yu6D+`1x5axj>H=tW=Poxp z71p{Q$17YNzzO}x-$srcr%NAcwgN^Mp{Q`$ZbN2UyZTqFM-!7+bKcV$0EK*xCg(*8 zkfPDyYlUsq!zrldqqB9vK|xFY>o6ymnV@RMQmsAeef3ZUR-zwDsGuvS8)@%6bc8^t z5LDk(3Y?f?u0|ytWiHba{Q4Q`LxJeCD*b?!U#Z<-mLE&|%?^!& zv|d5f^9`7iJ1^Ta7$hjh3J%0#l_VF6_x3#iM2aSX+a_EY>pRs!OT@M*|leuqe?zzAF$w2$xa>_OlOW zsCcKIgS3IJ)kBV{ViK{{K_^u1;Xhz1s1f{=H&R`C06Chl%o_0P&e}W#hY2*4+CJ!7 zQ!p#hYD(1A^P*Qf9YNF~zK$`2D*Y&Zr6Y{dLy1(W0VBW>N?;bJ(&lVHBSFJjKcjeZ zfTp7N$hi6uatF>&xbY( z`A5PO3@U##biq#S!U^OCAVl{cK|oNbzEM2n5~hG}E=O{ni-|hnPJ@O{4IGT{VdA0M z6>vZF*w{!JqMPhAtQhNj<=O*!g~%rt2m#EE_UVlt#0^gTqdUO-1#j~di&T^%#H$xq z11c6qb6nY0M-j+Uhu<0oGAE=Z-}tEL&XFxK>F$=8P6ChzF|TLKW?rkED|O zPjmt`OS!e=b`W#YOh)PdAJ(`r6*8={6!I;r^1q*>Z-LopTWfN$Ql^!fMY{96Ua5=F z$MaBB6>vnq)NO(m6fA4edGHCMgxodS(s6qls9LKYmnM{(28|-Bdh~0z=zKH^8nQ*d z))OWwv$_r2(oOiB(Mhz%fWZMqu3iu*_g|m=^-*I4gt^Qq<%U<494HRe&HY+;6R4v{ z^er?Wm3O!~`26l?h^NPvh8oADTUk&Ygp`*Z5xx*NWL1CVOtHC^L&GOtDx84Vw$N2!6@HotR6N z5JSYx@W_f>EBsw1X^y$sdibI&P2h!sO`o=Y&kv%q6YPdsR6K=vXz R*J?ds3?K4Ua0tr)008+=M^OL( literal 164 zcmV;V09*ebiwFP!0000014Ya+4#F@D1<<{x_)<3{nmsc&01l8+w~3U*RqQGpA5#V- zFJJ!ujkpsbs_x>Q>%C8nXI9a-PTV&4Pf<(8$_)#@jzU#~Ca$oH+@Xv^2pS2$$z&U> zDbp|xBOZ)7RD_%%ds?Uo*2d-R8Pvh8oADTUk&Ygp`*Z5xx*NWL1CVOtHC^L&GOtDx84Vw$N2!6@HotR6N z5JSYx@W_f>EBsw1X^y$sdibI&P2h!sO`o=Y&kv%q6YPdsR6K=vXz R*J?ds3?K4Ua0tr)008+=M^OL( literal 164 zcmV;V09*ebiwFP!0000014Ya+4#F@D1<<{x_)<3{nmsc&01l8+w~3U*RqQGpA5#V- zFJJ!ujkpsbs_x>Q>%C8nXI9a-PTV&4Pf<(8$_)#@jzU#~Ca$oH+@Xv^2pS2$$z&U> zDbp|xBOZ)7RD_%%ds?Uo*2d-R8