Deploy

Create a simple app

To create a new Phoenix project, open your terminal and run the following command:

mix phx.new ping_pong_app --no-html --no-ecto --no-dashboard

Navigate into your new project directory:

cd ping_pong_app

~/pg/cloud/ping_pong_app/lib/ping_pong_app_web/controllers/page_controller.ex

defmodule PingPongAppWeb.Controllers.PageController do
  use PingPongAppWeb, :controller

  def index(conn, _params) do
    data = %{
      message: "Hello, world!"
    }
    json(conn, data)
  end
end

~/pg/cloud/ping_pong_app/lib/ping_pong_app_web/router.ex

  scope "/api", PingPongAppWeb do
    pipe_through :api

    get "/ping", Controllers.PageController, :index
  end

Prepare a Dockerfile

~/pg/cloud/ping_pong_app/Dockerfile

FROM elixir:1.16.0-alpine as builder

RUN apk add --no-cache build-base git openssl-dev ca-certificates

WORKDIR /app

COPY mix.exs mix.lock ./
COPY config config/
COPY lib lib/
COPY priv priv/
COPY assets assets/

RUN mix deps.get --only prod
RUN mix deps.compile

ENV MIX_ENV=prod
RUN mix compile

RUN mix release

FROM alpine:3.18

RUN apk add --no-cache openssl ncurses-libs libstdc++

WORKDIR /app

COPY --from=builder /app/_build/prod/rel/ping_pong_app ./

ENV PORT=8080
EXPOSE 8080

CMD ["/app/bin/ping_pong_app", "start"]

google cloud

gcloud auth login
gcloud projects list
echo 'export GCLOUD_PROJECT_ID=<your project id>'
direnv allow
gcloud config set project $GCLOUD_PROJECT_ID

Build and Push Image

docker buildx create --name mybuilder --use
docker buildx inspect --bootstrap
brew install docker-credential-helper
gcloud auth configure-docker
docker buildx build \
  --platform linux/amd64 \
  -t gcr.io/$GCLOUD_PROJECT_ID/ping-pong-app:v1 \
  --push .
docker push gcr.io/$GCLOUD_PROJECT_ID/ping-pong-app:v1

Create a GKE cluster

gcloud container clusters create ping-pong-cluster \
    --zone us-central1-c \
    --num-nodes 1 \
    --machine-type e2-micro \
    --enable-ip-alias

Authenticates your local kubectl CLI with the GKE cluster:

gcloud components install gke-gcloud-auth-plugin
gcloud container clusters get-credentials ping-pong-cluster --zone us-central1-c
kubectl get node

Prepare k8s configuration

~/pg/cloud/ping_pong_app/k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ping-pong-deployment
  labels:
    app: ping-pong-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ping-pong-app
  template:
    metadata:
      labels:
        app: ping-pong-app
    spec:
      containers:
      - name: ping-pong-app
        image: gcr.io/YOUR_PROJECT_ID/ping-pong-app:v1 # Replace with your project ID
        ports:
        - containerPort: 8080
        env:
        - name: HOST
          value: "0.0.0.0"
        - name: PORT
          value: "8080"

~/pg/cloud/ping_pong_app/k8s/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: ping-pong-service
spec:
  selector:
    app: ping-pong-app # Selects pods with this label
  ports:
    - protocol: TCP
      port: 80 # The port the service exposes
      targetPort: 8080 # The port on the pod to forward traffic to
  type: LoadBalancer # Creates an external IP address

Deploy

kubectl apply -f k8s/
deployment.apps/ping-pong-deployment created
service/ping-pong-service created
kubectl get pods -l app=ping-pong-app

kubectl get pods -l app=ping-pong-app -o jsonpath='{.items[0].metadata.name}'

kubectl logs YOUR_POD_NAME

Visit your app

kubectl get service ping-pong-service

Clean up

kubectl delete -f k8s/
gcloud container clusters delete ping-pong-cluster --zone us-central1-c
gcloud container images list
gcloud container images list-tags gcr.io/$GCLOUD_PROJECT_ID/ping-pong-app
gcloud container images delete gcr.io/$GCLOUD_PROJECT_ID/ping-pong-app:v1