### ----------------------- # --- Stage: development # --- Purpose: Local development environment # --- https://hub.docker.com/_/golang # --- https://github.com/microsoft/vscode-remote-try-go/blob/master/.devcontainer/Dockerfile ### ----------------------- FROM golang:1.25.0-bookworm AS development # Avoid warnings by switching to noninteractive ENV DEBIAN_FRONTEND=noninteractive # Our Makefile / env fully supports parallel job execution ENV MAKEFLAGS "-j 8 --no-print-directory" # postgresql-support: Add the official postgres repo to install the matching postgresql-client tools of your stack # https://wiki.postgresql.org/wiki/Apt # run lsb_release -c inside the container to pick the proper repository flavor # e.g. stretch=>stretch-pgdg, buster=>buster-pgdg, bullseye=>bullseye-pgdg, bookworm=>bookworm-pgdg RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main" \ | tee /etc/apt/sources.list.d/pgdg.list \ && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc \ | apt-key add - # Setup GPG key to install Trivy to locally scan for vulnerabilities RUN mkdir -m 0755 -p /etc/apt/keyrings/ \ && wget -O- https://aquasecurity.github.io/trivy-repo/deb/public.key | \ gpg --dearmor | \ tee /etc/apt/keyrings/trivy.gpg > /dev/null; \ chmod 644 /etc/apt/keyrings/trivy.gpg \ && echo "deb [signed-by=/etc/apt/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb bookworm main" \ | tee /etc/apt/sources.list.d/trivy.list # Install required system dependencies RUN apt-get update \ && apt-get install -y \ # # Mandadory minimal linux packages # Installed at development stage and app stage # Do not forget to add mandadory linux packages to the final app Dockerfile stage below! # # -- START MANDADORY -- ca-certificates \ # --- END MANDADORY --- # # Development specific packages # Only installed at development stage and NOT available in the final Docker stage # based upon # https://github.com/microsoft/vscode-remote-try-go/blob/master/.devcontainer/Dockerfile # https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh # # icu-devtools: https://stackoverflow.com/questions/58736399/how-to-get-vscode-liveshare-extension-working-when-running-inside-vscode-remote # graphviz: https://github.com/google/pprof#building-pprof # -- START DEVELOPMENT -- apt-utils \ dialog \ openssh-client \ less \ iproute2 \ procps \ lsb-release \ locales \ sudo \ bash-completion \ bsdmainutils \ graphviz \ xz-utils \ postgresql-client-17 \ icu-devtools \ tmux \ rsync \ trivy \ # --- END DEVELOPMENT --- # && apt-get clean \ && rm -rf /var/lib/apt/lists/* # env/vscode support: LANG must be supported, requires installing the locale package first # https://github.com/Microsoft/vscode/issues/58015 # https://stackoverflow.com/questions/28405902/how-to-set-the-locale-inside-a-debian-ubuntu-docker-container RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \ dpkg-reconfigure --frontend=noninteractive locales && \ update-locale LANG=en_US.UTF-8 ENV LANG en_US.UTF-8 # sql pgFormatter: Integrates with vscode-pgFormatter (we pin pgFormatter.pgFormatterPath for the extension to this version) # requires perl to be installed # https://github.com/bradymholt/vscode-pgFormatter/commits/master # https://github.com/darold/pgFormatter/releases RUN mkdir -p /tmp/pgFormatter \ && cd /tmp/pgFormatter \ && wget https://github.com/darold/pgFormatter/archive/v5.5.tar.gz \ && tar xzf v5.5.tar.gz \ && cd pgFormatter-5.5 \ && perl Makefile.PL \ && make && make install \ && rm -rf /tmp/pgFormatter # go gotestsum: (this package should NOT be installed via go get) # https://github.com/gotestyourself/gotestsum/releases RUN mkdir -p /tmp/gotestsum \ && cd /tmp/gotestsum \ && ARCH="$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/)" \ && wget "https://github.com/gotestyourself/gotestsum/releases/download/v1.12.3/gotestsum_1.12.3_linux_${ARCH}.tar.gz" \ && tar xzf "gotestsum_1.12.3_linux_${ARCH}.tar.gz" \ && cp gotestsum /usr/local/bin/gotestsum \ && rm -rf /tmp/gotestsum # go linting: (this package should NOT be installed via go get) # https://github.com/golangci/golangci-lint#binary # https://github.com/golangci/golangci-lint/releases RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \ | sh -s -- -b $(go env GOPATH)/bin v2.4.0 # go swagger: (this package should NOT be installed via go get) # https://github.com/go-swagger/go-swagger/releases RUN ARCH="$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/)" \ && curl -o /usr/local/bin/swagger -L'#' \ "https://github.com/go-swagger/go-swagger/releases/download/v0.29.0/swagger_linux_${ARCH}" \ && chmod +x /usr/local/bin/swagger # lichen: go license util # TODO: Install from static binary as soon as it becomes available. # https://github.com/uw-labs/lichen/tags RUN go install github.com/uw-labs/lichen@v0.1.7 # cobra-cli: cobra cmd scaffolding generator # TODO: Install from static binary as soon as it becomes available. # https://github.com/spf13/cobra-cli/releases RUN go install github.com/spf13/cobra-cli@v1.3.0 # govulncheck: go vulnerability checker RUN go install golang.org/x/vuln/cmd/govulncheck@latest # changie: a tool to help manage changelogs RUN go install github.com/miniscruff/changie@v1.21.0 # watchexec # https://github.com/watchexec/watchexec/releases RUN mkdir -p /tmp/watchexec \ && cd /tmp/watchexec \ && wget https://github.com/watchexec/watchexec/releases/download/v1.25.1/watchexec-1.25.1-$(arch)-unknown-linux-musl.tar.xz \ && tar xf watchexec-1.25.1-$(arch)-unknown-linux-musl.tar.xz \ && cp watchexec-1.25.1-$(arch)-unknown-linux-musl/watchexec /usr/local/bin/watchexec \ && rm -rf /tmp/watchexec # yq # https://github.com/mikefarah/yq/releases RUN mkdir -p /tmp/yq \ && cd /tmp/yq \ && ARCH="$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/)" \ && wget "https://github.com/mikefarah/yq/releases/download/v4.40.5/yq_linux_${ARCH}.tar.gz" \ && tar xzf "yq_linux_${ARCH}.tar.gz" \ && cp "yq_linux_${ARCH}" /usr/local/bin/yq \ && rm -rf /tmp/yq # spectral: OpenAPI / JSON schema linter # https://github.com/stoplightio/spectral RUN curl -L https://raw.github.com/stoplightio/spectral/master/scripts/install.sh | sh # gsdev # The sole purpose of the "gsdev" cli util is to provide a handy short command for the following (all args are passed): # go run -tags scripts /app/scripts/main.go "$@" RUN printf '#!/bin/bash\nset -Eeo pipefail\ncd /app && go run -tags scripts ./scripts/main.go "$@"' > /usr/bin/gsdev && chmod 755 /usr/bin/gsdev # linux permissions / vscode support: Add user to avoid linux file permission issues # Detail: Inside the container, any mounted files/folders will have the exact same permissions # as outside the container - including the owner user ID (UID) and group ID (GID). # Because of this, your container user will either need to have the same UID or be in a group with the same GID. # The actual name of the user / group does not matter. The first user on a machine typically gets a UID of 1000, # so most containers use this as the ID of the user to try to avoid this problem. # 2020-04: docker-compose does not support passing id -u / id -g as part of its config, therefore we assume uid 1000 # https://code.visualstudio.com/docs/remote/containers-advanced#_adding-a-nonroot-user-to-your-dev-container # https://code.visualstudio.com/docs/remote/containers-advanced#_creating-a-nonroot-user ARG USERNAME=development ARG USER_UID=1000 ARG USER_GID=$USER_UID RUN groupadd --gid $USER_GID $USERNAME \ && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ && chmod 0440 /etc/sudoers.d/$USERNAME # vscode support: cached extensions install directory # https://code.visualstudio.com/docs/remote/containers-advanced#_avoiding-extension-reinstalls-on-container-rebuild RUN mkdir -p /home/$USERNAME/.vscode-server/extensions \ /home/$USERNAME/.vscode-server-insiders/extensions \ && chown -R $USERNAME \ /home/$USERNAME/.vscode-server \ /home/$USERNAME/.vscode-server-insiders # linux permissions / vscode support: chown $GOPATH so $USERNAME can directly work with it # Note that this should be the final step after installing all build deps RUN mkdir -p /$GOPATH/pkg && chown -R $USERNAME /$GOPATH # https://code.visualstudio.com/remote/advancedcontainers/persist-bash-history RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/home/$USERNAME/commandhistory/.bash_history" \ && mkdir /home/$USERNAME/commandhistory \ && touch /home/$USERNAME/commandhistory/.bash_history \ && chown -R $USERNAME /home/$USERNAME/commandhistory \ && echo "$SNIPPET" >> "/home/$USERNAME/.bashrc" # $GOBIN is where our own compiled binaries will live and other go.mod / VSCode binaries will be installed. # It should always come AFTER our other $PATH segments and should be earliest targeted in stage "builder", # as /app/bin will the shadowed by a volume mount via docker-compose! # E.g. "which golangci-lint" should report "/go/bin" not "/app/bin" (where VSCode will place it). # https://github.com/go-modules-by-example/index/blob/master/010_tools/README.md#walk-through WORKDIR /app ENV GOBIN /app/bin ENV PATH $PATH:$GOBIN ### ----------------------- # --- Stage: builder # --- Purpose: Statically built binaries and CI environment ### ----------------------- FROM development AS builder WORKDIR /app COPY Makefile /app/Makefile COPY --chmod=0755 rksh /app/rksh COPY go.mod /app/go.mod COPY go.sum /app/go.sum RUN make modules RUN make tools COPY . /app/ RUN make go-build ### ----------------------- # --- Stage: app # --- Purpose: Image for actual deployment # --- Prefer https://github.com/GoogleContainerTools/distroless over # --- debian:buster-slim https://hub.docker.com/_/debian (if you need apt-get). ### ----------------------- # Distroless images are minimal and lack shell access. # https://github.com/GoogleContainerTools/distroless/blob/master/base/README.md # The :debug image provides a busybox shell to enter (base-debian10 only, not static). # https://github.com/GoogleContainerTools/distroless#debug-images FROM gcr.io/distroless/base-debian12:debug AS app # FROM debian:bookworm-slim AS app # RUN apt-get update \ # && apt-get install -y \ # # # # Mandadory minimal linux packages # # Installed at development stage and app stage # # Do not forget to add mandadory linux packages to the base development Dockerfile stage above! # # # # -- START MANDADORY -- # ca-certificates \ # # --- END MANDADORY --- # # # && apt-get clean \ # && rm -rf /var/lib/apt/lists/* COPY --from=builder /app/bin/app /app/ COPY --from=builder /app/api/swagger.yml /app/api/ COPY --from=builder /app/assets /app/assets/ COPY --from=builder /app/migrations /app/migrations/ COPY --from=builder /app/web /app/web/ WORKDIR /app # Must comply to vector form # https://github.com/GoogleContainerTools/distroless#entrypoints # Sample usage of this image: # docker run help # docker run db migrate # docker run db seed # docker run env # docker run probe readiness # docker run probe liveness # docker run server # docker run server --migrate ENTRYPOINT ["/app/app"] CMD ["server", "--migrate"]