Skip to content

Commit

Permalink
Optimize CI/CD: Implement Nix-based dev builds (#28)
Browse files Browse the repository at this point in the history
* chore: implement nix base container image build

* chore: switch dev workflow to nix base image build
  • Loading branch information
nully0x authored Oct 4, 2024
1 parent 897908b commit f2fc86f
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 54 deletions.
120 changes: 66 additions & 54 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Docker Publish
name: Docker Build and Publish

on:
push:
branches: [ "main" ]
branches: ["main"]
release:
types: [created]

Expand All @@ -13,82 +13,90 @@ env:
CARGO_TERM_COLOR: always

jobs:
build-and-push:
build-and-push-dev:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Install Rust
uses: actions-rs/toolchain@v1
- name: Install Nix
uses: cachix/install-nix-action@v20
with:
profile: minimal
toolchain: stable
nix_path: nixpkgs=channel:nixos-unstable
extra_nix_config: |
experimental-features = nix-command flakes
accept-flake-config = true
keep-outputs = true
keep-derivations = true
- name: Cache cargo registry
- name: Setup Nix caching
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
~/.cache/nix
key: ${{ runner.os }}-nix-${{ hashFiles('**/docker-image.nix', '**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
${{ runner.os }}-nix-
- name: Install cargo-chef
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-chef
- name: Build with Nix
run: |
nix-build build-image.nix
docker load < result
- name: Prepare recipe
run: cargo chef prepare --recipe-path recipe.json
- name: Verify image contents
run: |
docker run --rm hxckr-core:latest ls -l /app
docker run --rm hxckr-core:latest ls -l /app/migrations
docker run --rm hxckr-core:latest cat /app/entrypoint.sh
docker run --rm hxckr-core:latest which diesel
docker run --rm hxckr-core:latest diesel --version
- name: Cache dependencies
uses: actions/cache@v3
- name: Login to DockerHub
uses: docker/login-action@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-chef-${{ hashFiles('**/recipe.json') }}
restore-keys: |
${{ runner.os }}-cargo-chef-
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ env.DOCKERHUB_TOKEN }}

- name: Build dependencies
run: cargo chef cook --release --recipe-path recipe.json
- name: Push Docker image
run: |
docker tag hxckr-core:latest ${{ env.IMAGE_NAME }}:dev
docker tag hxckr-core:latest ${{ env.IMAGE_NAME }}:${{ github.sha }}
docker push ${{ env.IMAGE_NAME }}:dev
docker push ${{ env.IMAGE_NAME }}:${{ github.sha }}
- name: Build project
run: cargo build --release --all-features
- name: Print image size and details
run: |
docker image ls ${{ env.IMAGE_NAME }}:dev
docker history ${{ env.IMAGE_NAME }}:dev
build-and-push-prod:
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
install: true
profile: minimal
toolchain: stable

- name: Build project
run: |
cargo install cargo-chef
cargo chef prepare --recipe-path recipe.json
cargo chef cook --release --recipe-path recipe.json
cargo build --release --all-features
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ env.DOCKERHUB_TOKEN }}

- name: Build and push Docker image (Development)
if: github.event_name == 'push'
uses: docker/build-push-action@v4
with:
context: .
file: Dockerfile.dev
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.IMAGE_NAME }}:dev
${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache,mode=max

- name: Build and push Docker image (Production)
if: github.event_name == 'release'
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
Expand All @@ -101,12 +109,16 @@ jobs:
cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache,mode=max

- name: Run migrations (Production)
if: github.event_name == 'release'
- name: Run migrations
env:
DATABASE_URL: ${{ secrets.PRODUCTION_DATABASE_URL }}
run: |
docker run --rm \
-e DATABASE_URL \
${{ env.IMAGE_NAME }}:${{ github.ref_name }} \
diesel migration run
- name: Print image size and details
run: |
docker image ls ${{ env.IMAGE_NAME }}:${{ github.ref_name }}
docker history ${{ env.IMAGE_NAME }}:${{ github.ref_name }}
81 changes: 81 additions & 0 deletions build-image.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{ pkgs ? import <nixpkgs> {} }:

let
rustOverlay = import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz");
pkgs = import <nixpkgs> { overlays = [ rustOverlay ]; };
rust = pkgs.rust-bin.stable."1.80.0".default;

hxckr-core = pkgs.rustPlatform.buildRustPackage {
pname = "hxckr-core";
version = "0.1.0";
src = ./.;
cargoLock.lockFile = ./Cargo.lock;

nativeBuildInputs = [ pkgs.pkg-config ];
buildInputs = [ pkgs.openssl pkgs.postgresql ];

doCheck = false;

# Optimize the build
RUSTFLAGS = "-C target-cpu=native -C opt-level=3";
CARGO_PROFILE_RELEASE_LTO = "thin";
CARGO_PROFILE_RELEASE_CODEGEN_UNITS = "16";
CARGO_PROFILE_RELEASE_OPT_LEVEL = "3";
CARGO_PROFILE_RELEASE_PANIC = "abort";
CARGO_PROFILE_RELEASE_INCREMENTAL = "false";
CARGO_PROFILE_RELEASE_DEBUG = "0";

# Strip debug symbols
stripAllList = [ "bin" ];

# Use all available cores
NIX_BUILD_CORES = 0;
preBuild = ''
export CARGO_BUILD_JOBS=$NIX_BUILD_CORES
'';
};

entrypoint-script = ./entrypoint.dev.sh;

in
pkgs.dockerTools.buildLayeredImage {
name = "hxckr-core";
tag = "latest";
created = "now";

contents = [
hxckr-core
pkgs.diesel-cli
pkgs.bash
pkgs.coreutils
pkgs.findutils
pkgs.openssl
pkgs.postgresql.lib
pkgs.cacert
pkgs.libiconv
];

extraCommands = ''
mkdir -p app/migrations
cp -r ${./migrations}/* app/migrations/
cp ${entrypoint-script} app/entrypoint.sh
chmod +x app/entrypoint.sh
'';

config = {
Cmd = [ "/app/entrypoint.sh" ];
Env = [
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
"PATH=/bin:${hxckr-core}/bin:${pkgs.diesel-cli}/bin:${pkgs.findutils}/bin"
"LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath [
pkgs.openssl
pkgs.postgresql.lib
pkgs.libiconv
]}"
];
WorkingDir = "/app";
ExposedPorts = {
"4925/tcp" = {};
};
};
}

0 comments on commit f2fc86f

Please sign in to comment.