diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index c54bb86..0000000 --- a/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -# syntax = docker/dockerfile:1.2 - -# We use a multi-stage build to end up with a very small final image -FROM alpine:latest AS builder - -ENV PATH "$PATH:/root/.cargo/bin" - -WORKDIR /usr/src/app - -# Install build dependencies, rustup & rust's nightly build & toolchain -RUN apk update && apk add --no-cache openssl-dev build-base curl && \ - { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly; } - -# Copy source code over to builder -COPY Cargo.toml Cargo.lock ./ -COPY src/ ./src/ - -# Run the tests, don't want no broken docker image -# And then finally, build the project -# Thank the lords that this article exists -# https://users.rust-lang.org/t/sigsegv-with-program-linked-against-openssl-in-an-alpine-container/52172 -# TODO add what these flags do & why they work -# NOTE: cargo install auto-appends bin to the path -RUN --mount=type=cache,target=/usr/src/app/target RUSTFLAGS="-C target-feature=-crt-static" cargo test && \ - RUSTFLAGS="-C target-feature=-crt-static" cargo install --path . --bin fej --root /usr/local - - -# Now, we create the actual image -FROM alpine:latest - -# Install some dynamic libraries needed for everything to work -RUN apk update && apk add --no-cache openssl libgcc - -# Copy binary over to final image -COPY --from=builder /usr/local/bin/fej /usr/local/bin/fej - -CMD ["/usr/local/bin/fej"] diff --git a/Makefile b/Makefile index ab50282..c276d79 100644 --- a/Makefile +++ b/Makefile @@ -1,35 +1,36 @@ -IMAGE := chewingbever/fej - - all: debug .PHONY: all # Builds debug: - @ cargo build + @ ./build -m dev .PHONY: debug release: - @ cargo build --release + @ ./build -m rel .PHONY: release -image: Dockerfile - @ ./build '$(IMAGE)' -.PHONY: image - push: - @ ./build '$(IMAGE)' push + @ ./build -m prod -a push .PHONY: push # Run run: - @ RUST_BACKTRACE=1 cargo run --bin fej + @ ./build -m dev -a run .PHONY: run +stop: + @ docker stop -t 2 fej +.PHONY: stop + +logs: + @ docker logs -f fej +.PHONY: logs + # Testing test: - @ cargo test --no-fail-fast + @ ./build -m dev -a run -l -- test --no-fail-fast .PHONY: test format: diff --git a/build b/build index 8abbc39..32b04aa 100755 --- a/build +++ b/build @@ -1,10 +1,21 @@ #!/usr/bin/env bash -# Simple guard to check input args -[[ $# -eq 1 ]] || [[ $# -eq 2 ]] || { - >&2 echo "Usage: ./build IMAGE [ACTION]" - exit 1 -} +image="chewingbever/fej" +# Should be either dev or rel +mode="dev" +action="" +attach="--detach" + +while getopts ":i:m:a:l" c; do + case $c in + i ) image="$OPTARG" ;; + m ) mode="$OPTARG" ;; + a ) action="$OPTARG" ;; + l ) attach="" ;; + ? ) exit 1 ;; + esac +done +shift $((OPTIND-1)) # Extract current version from Cargo.toml & get current branch patch_version="$(grep -Po '(?<=version = ").*(?=")' Cargo.toml | head -n1)" @@ -25,31 +36,58 @@ else fi -# Run the actual build command -DOCKER_BUILDKIT=1 docker build -t "$1:$tags" . +# First, we build the builder +DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile.builder -t "$image-builder:latest" . -if [[ "$2" = push ]]; then +# Run the actual build command +if [ "$mode" = "rel" ]; then + DOCKER_BUILDKIT=1 docker build -t "$image:$tags" -f docker/Dockerfile.rel . + +elif [[ "$mode" = "dev" ]]; then + DOCKER_BUILDKIT=1 docker build -t "$image-dev:$tags" -f docker/Dockerfile.dev . + +else + >&2 echo "Invalid mode." + exit 1 + +fi + +if [[ "$action" = push ]]; then [[ "$branch" =~ ^develop|master$ ]] || { >&2 echo "You can only push from develop or master." exit 2 } + [[ "$mode" = "rel" ]] || { + >&2 echo "You can only push release builds." + exit 3 + } + for tag in "${tags[@]}"; do # Create the tag - docker tag "$1:$tags" "$1:$tag" + docker tag "$image:$tags" "$image:$tag" # Push the tag - docker push "$1:$tag" + docker push "$image:$tag" # Remove the tag again, if it's not the main tag - [[ "$tag" != "$tags" ]] && docker rmi "$1:$tag" + [[ "$tag" != "$tags" ]] && docker rmi "$image:$tag" done - elif [[ "$2" = run ]]; then - docker run \ + elif [[ "$action" = run ]]; then + if [[ "$mode" = "dev" ]]; then + # Create caching volumes if needed (they need to be named) + docker volume create fej_build-cache + docker volume create fej_registry-cache + + flags="-v fej_build-cache:/usr/src/app/target -v fej_registry-cache:/root/.cargo/registry" + fi + + docker run $attach $flags \ --rm \ --interactive \ --tty \ --publish 8000:8000 \ - "$1:$tags" + --name fej \ + "$image$([[ "$mode" != "rel" ]] && echo "-dev"):$tags" "$@" fi diff --git a/docker/Dockerfile.builder b/docker/Dockerfile.builder new file mode 100644 index 0000000..84d09ff --- /dev/null +++ b/docker/Dockerfile.builder @@ -0,0 +1,19 @@ +# We use a multi-stage build to end up with a very small final image +FROM alpine:latest AS builder + +ARG MODE +ARG RUN_TESTS + +ENV PATH "$PATH:/root/.cargo/bin" +# Needed for proper compiling of openssl-dev +ENV RUSTFLAGS="-C target-feature=-crt-static" + +WORKDIR /usr/src/app + +# Install build dependencies, rustup & rust's nightly build & toolchain +RUN apk update && apk add --no-cache openssl-dev build-base curl && \ + { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly; } + +# Copy source code over to builder +COPY Cargo.toml Cargo.lock ./ +COPY src/ ./src/ diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev new file mode 100644 index 0000000..a1a1e92 --- /dev/null +++ b/docker/Dockerfile.dev @@ -0,0 +1,6 @@ +FROM chewingbever/fej-builder:latest + +ENV RUST_BACKTRACE=1 + +ENTRYPOINT ["cargo"] +CMD ["run"] diff --git a/docker/Dockerfile.rel b/docker/Dockerfile.rel new file mode 100644 index 0000000..4d40ef2 --- /dev/null +++ b/docker/Dockerfile.rel @@ -0,0 +1,22 @@ +FROM chewingbever/fej-builder:latest AS builder + +# And then finally, build the project +# Thank the lords that this article exists +# https://users.rust-lang.org/t/sigsegv-with-program-linked-against-openssl-in-an-alpine-container/52172 +# TODO add what these flags do & why they work +# NOTE: cargo install auto-appends bin to the path +RUN --mount=type=cache,target=/usr/src/app/target \ + --mount=type=cache,target=/root/.cargo/registry \ + cargo install --path . --bin fej --root /usr/local + + +# Now, we create the actual image +FROM alpine:latest + +# Install some dynamic libraries needed for everything to work +RUN apk update && apk add --no-cache openssl libgcc + +# Copy binary over to final image +COPY --from=builder /usr/local/bin/fej /usr/local/bin/fej + +CMD ["/usr/local/bin/fej"]