From 30e4cb4e4af3a6eebd3b4fb431828d284a72a10a Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Fri, 19 Apr 2024 16:11:33 +0200 Subject: use nix to build docker images --- .dockerignore | 10 ---- .envrc | 1 + .gitignore | 1 + Dockerfile | 34 ------------- flake.nix | 33 ++++++------- fly.toml | 3 +- nix/default.nix | 71 +++++++++++++++++++++++++++ nix/gomod2nix.toml | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++ nix/scripts.nix | 49 ++++++++++++++++++ 9 files changed, 280 insertions(+), 64 deletions(-) delete mode 100644 .dockerignore delete mode 100644 Dockerfile create mode 100644 nix/default.nix create mode 100644 nix/gomod2nix.toml create mode 100644 nix/scripts.nix diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 48be77d..0000000 --- a/.dockerignore +++ /dev/null @@ -1,10 +0,0 @@ -* -!cmd -!server.go -!content -!internal -!static -!templates -!config.toml -!go.mod -!go.sum diff --git a/.envrc b/.envrc index 3550a30..5973c50 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,2 @@ +watch_file nix/* use flake diff --git a/.gitignore b/.gitignore index ae7753d..7dc1da8 100644 --- a/.gitignore +++ b/.gitignore @@ -172,3 +172,4 @@ dist /.compressstamp /.formatstamp /server +/result diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index bf8da92..0000000 --- a/Dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -# syntax = docker/dockerfile:1 - -ARG GO_VERSION=1.22.1 -FROM docker.io/library/golang:${GO_VERSION} as builder - -WORKDIR /app - -COPY --link go.mod . -RUN go mod download - -COPY --link . . - -# RUN go vet ./... -ENV ENV=production -RUN go run ./cmd/build - -ENV GOOS=linux GOARCH=amd64 CGO_ENABLED=0 -RUN go build server.go - -# Final stage for app image -FROM gcr.io/distroless/static - -WORKDIR /app - -# Copy built application -COPY --link config.toml . -COPY --from=builder /app/server server - -# Start the server by default, this can be overwritten at runtime -EXPOSE 3000 -EXPOSE 9091 - -ENV ENV=production -CMD [ "/app/server" ] diff --git a/flake.nix b/flake.nix index 4d78ce1..78a2c53 100644 --- a/flake.nix +++ b/flake.nix @@ -12,37 +12,34 @@ inputs.flake-utils.follows = "utils"; }; - outputs = { nixpkgs, utils, gomod2nix, ... }: + outputs = { self, nixpkgs, utils, gomod2nix, ... }: utils.lib.eachDefaultSystem (system: let - pkgs = nixpkgs.legacyPackages.${system}; - nativeBuildInputs = with pkgs; [ - git - go - ]; + pkgs = import nixpkgs { + inherit system; + overlays = [ gomod2nix.overlays.default ]; + }; + nativeBuildInputs = with pkgs; [ go ]; + packages = import ./nix/default.nix { + inherit pkgs self; + }; in - rec { + { + inherit packages; devShells = { default = pkgs.mkShell { packages = with pkgs; [ gopls gotools go-tools - go-licenses gomod2nix.packages.${system}.default gci flyctl - (writeShellScriptBin "watch-builder" '' - ${pkgs.watchexec}/bin/watchexec -r -w flake.nix --shell fish "direnv exec . watchexec -i server.go -i public -r go run ./cmd/build $@" - '') - (writeShellScriptBin "watch-server" '' - ${pkgs.watchexec}/bin/watchexec -r -w flake.nix --shell fish "direnv exec . watchexec -r go run ./server.go $@" - '') - (writeShellScriptBin "check-licenses" '' - ${pkgs.go-licenses}/bin/go-licenses check --include_tests ./... --disallowed_types=restricted,forbidden - '') - ] ++ nativeBuildInputs; + ] + ++ (import ./nix/scripts.nix { + inherit pkgs; + }); }; }; }); diff --git a/fly.toml b/fly.toml index cd2269d..5b7f722 100644 --- a/fly.toml +++ b/fly.toml @@ -7,8 +7,7 @@ app = "alanpearce-eu" primary_region = "ams" [build] - [build.args] - GO_VERSION = "1.22.1" + image = "registry.fly.io/alanpearce-eu" [env] PORT = "3000" diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 0000000..a04131b --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,71 @@ +{ pkgs, self }: +let + revision = "${self.lastModifiedDate}-${self.shortRev or "dirty"}"; + version = "unstable-${self.shortRev or "dirty"}"; + mkDocker = server: + let + PORT = 3000; + in + pkgs.dockerTools.streamLayeredImage { + name = "registry.fly.io/alanpearce-eu"; + tag = revision; + contents = [ server ]; + config = { + Cmd = [ "website" ]; + Env = [ + "PRODUCTION=true" + "PORT=${builtins.toString PORT}" + "ROOT=public" + ]; + ExposedPorts = { + "${builtins.toString PORT}/tcp" = { }; + }; + }; + }; +in +rec { + default = server; + builder = pkgs.buildGoApplication { + pname = "website-builder"; + inherit version; + src = with pkgs.lib.fileset; toSource { + root = ./..; + fileset = unions [ + ./../go.mod + ./../go.sum + ./../cmd + ./../internal + ]; + }; + modules = ./gomod2nix.toml; + subPackages = [ "cmd/build" ]; + }; + server = pkgs.buildGoApplication { + pname = "website"; + inherit version; + CGO_ENABLED = 0; + src = with pkgs.lib.fileset; toSource { + root = ./..; + fileset = unions [ + ./../go.mod + ./../go.sum + ./../server.go + ./../internal + ./../config.toml + ./../content + ./../static + ./../templates + ]; + }; + buildInputs = [ builder ]; + prePatch = '' + ${builder}/bin/build + ''; + modules = ./gomod2nix.toml; + ldflags = [ "-s" "-w" ]; + }; + docker = mkDocker server; + docker-aarch64-linux = mkDocker (self.packages.aarch64-linux.server); + docker-x86_64-linux = mkDocker (self.packages.x86_64-linux.server); + fly = docker-x86_64-linux; +} diff --git a/nix/gomod2nix.toml b/nix/gomod2nix.toml new file mode 100644 index 0000000..83643b5 --- /dev/null +++ b/nix/gomod2nix.toml @@ -0,0 +1,142 @@ +schema = 3 + +[mod] + [mod."github.com/BurntSushi/toml"] + version = "v1.2.1" + hash = "sha256-Z1dlsUTjF8SJZCknYKt7ufJz8NPGg9P9+W17DQn+LO0=" + [mod."github.com/PuerkitoBio/goquery"] + version = "v1.9.1" + hash = "sha256-HlO8KL0FWs7qZk56wcVAn/y080PfK910HyIVo9y9lvM=" + [mod."github.com/a-h/htmlformat"] + version = "v0.0.0-20240418170242-387207ca8d01" + hash = "sha256-6EhDObXsE0ObvaHCPXl2pHXhKaEYr/mUZNhLPcUz3L0=" + replaced = "github.com/alanpearce/htmlformat" + [mod."github.com/adrg/frontmatter"] + version = "v0.2.0" + hash = "sha256-WJsVcdCpkIkjqUz5fJOFStZYwQlrcFzQ6+mZatZiimo=" + [mod."github.com/andybalholm/brotli"] + version = "v1.1.0" + hash = "sha256-njLViV4v++ZdgOWGWzlvkefuFvA/nkugl3Ta/h1nu/0=" + [mod."github.com/andybalholm/cascadia"] + version = "v1.3.2" + hash = "sha256-Nc9SkqJO/ecincVcUBFITy24TMmMGj5o0Q8EgdNhrEk=" + [mod."github.com/ansrivas/fiberprometheus/v2"] + version = "v2.6.1" + hash = "sha256-C8WChMGD3fJucEqkUEu4kMGdP75xXCgVOLdxJu0x3jI=" + [mod."github.com/antchfx/xmlquery"] + version = "v1.4.0" + hash = "sha256-ReWP6CPDvvWUd7vY0qIP4qyxvrotXrx9HXbGbeProP4=" + [mod."github.com/antchfx/xpath"] + version = "v1.3.0" + hash = "sha256-SU+Tnf5c9vsDCrY1BVKjqYLhB91xt9oHBS5bicbs2cA=" + [mod."github.com/ardanlabs/conf/v3"] + version = "v3.1.7" + hash = "sha256-7H53l0JN5Q6hkAgBivVQ8lFd03oNmP1IG8ihzLKm2CQ=" + [mod."github.com/beorn7/perks"] + version = "v1.0.1" + hash = "sha256-h75GUqfwJKngCJQVE5Ao5wnO3cfKD9lSIteoLp/3xJ4=" + [mod."github.com/cespare/xxhash/v2"] + version = "v2.2.0" + hash = "sha256-nPufwYQfTkyrEkbBrpqM3C2vnMxfIz6tAaBmiUP7vd4=" + [mod."github.com/deckarep/golang-set/v2"] + version = "v2.6.0" + hash = "sha256-ni1XK75Q8iBBmxgoyZTedP4RmrUPzFC4978xB4HKdfs=" + [mod."github.com/getsentry/sentry-go"] + version = "v0.27.0" + hash = "sha256-PTkTzVNogqFA/5rc6INLY6RxK5uR1AoJFOO+pOPdE7Q=" + [mod."github.com/gofiber/adaptor/v2"] + version = "v2.2.1" + hash = "sha256-hQLeFAC3oRQA14sUK5kBfl+dbqYmULM9TA0bDgNhfp4=" + [mod."github.com/gofiber/contrib/fibersentry"] + version = "v1.0.4" + hash = "sha256-feTWuq9aANPm16IpB1ZLZD4gZGt3Fs8Rr2d373Dlzqw=" + [mod."github.com/gofiber/fiber/v2"] + version = "v2.52.4" + hash = "sha256-Lp6btwX5ZPo09IrCPz+f7fIztrI9W/sTULBRqAvXJu0=" + [mod."github.com/golang/groupcache"] + version = "v0.0.0-20210331224755-41bb18bfe9da" + hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0=" + [mod."github.com/golang/protobuf"] + version = "v1.5.3" + hash = "sha256-svogITcP4orUIsJFjMtp+Uv1+fKJv2Q5Zwf2dMqnpOQ=" + [mod."github.com/google/uuid"] + version = "v1.6.0" + hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw=" + [mod."github.com/klauspost/compress"] + version = "v1.17.8" + hash = "sha256-8rgCCfHX29le8m6fyVn6gwFde5TPUHjwQqZqv9JIubs=" + [mod."github.com/kr/text"] + version = "v0.1.0" + hash = "sha256-QT65kTrNypS5GPWGvgnCpGLPlVbQAL4IYvuqAKhepb4=" + [mod."github.com/mattn/go-colorable"] + version = "v0.1.13" + hash = "sha256-qb3Qbo0CELGRIzvw7NVM1g/aayaz4Tguppk9MD2/OI8=" + [mod."github.com/mattn/go-isatty"] + version = "v0.0.20" + hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ=" + [mod."github.com/mattn/go-runewidth"] + version = "v0.0.15" + hash = "sha256-WP39EU2UrQbByYfnwrkBDoKN7xzXsBssDq3pNryBGm0=" + [mod."github.com/matttproud/golang_protobuf_extensions"] + version = "v1.0.4" + hash = "sha256-uovu7OycdeZ2oYQ7FhVxLey5ZX3T0FzShaRldndyGvc=" + [mod."github.com/otiai10/copy"] + version = "v1.14.0" + hash = "sha256-xsaL1ddkPS544y0Jv7u/INUALBYmYq29ddWvysLXk4A=" + [mod."github.com/philhofer/fwd"] + version = "v1.1.2" + hash = "sha256-N+jWn8FSjVlb/OAWmvLTm2G5/ckIkhzSPePXoeymfyA=" + [mod."github.com/pkg/errors"] + version = "v0.9.1" + hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" + [mod."github.com/prometheus/client_golang"] + version = "v1.16.0" + hash = "sha256-P/b4/8m1ztF0fCLSJ+eRXN74Bncx2vjOJx7nFl2QEg4=" + [mod."github.com/prometheus/client_model"] + version = "v0.4.0" + hash = "sha256-4P0sPWpxa69gGM6zm3dA06cH6twaeopq22VVDJjucHA=" + [mod."github.com/prometheus/common"] + version = "v0.44.0" + hash = "sha256-8n3gSWKDSJtGfOQgxsiCGyTnUjb5hvSxJi/hPcrE5Oo=" + [mod."github.com/prometheus/procfs"] + version = "v0.11.0" + hash = "sha256-dfbKDyKmL+BNGVuvEZmw1CiGBiwqUADxJKkIi1Sbv1Y=" + [mod."github.com/rivo/uniseg"] + version = "v0.4.7" + hash = "sha256-rDcdNYH6ZD8KouyyiZCUEy8JrjOQoAkxHBhugrfHjFo=" + [mod."github.com/shengyanli1982/law"] + version = "v0.1.12" + hash = "sha256-TWkgqfmJ9Zhr+1weI+zN0lyJfJdjpLbyQ/zh1EBBpow=" + [mod."github.com/tinylib/msgp"] + version = "v1.1.8" + hash = "sha256-nwTpHiEe0pjloZosGmS+z1ZcsVm5dW4OaPhzJG2wAng=" + [mod."github.com/valyala/bytebufferpool"] + version = "v1.0.0" + hash = "sha256-I9FPZ3kCNRB+o0dpMwBnwZ35Fj9+ThvITn8a3Jr8mAY=" + [mod."github.com/valyala/fasthttp"] + version = "v1.52.0" + hash = "sha256-Gmcd4N4VOqI7Pl9Trb2ifDhaCU/AjEpuVdyNGGww5zc=" + [mod."github.com/valyala/tcplisten"] + version = "v1.0.0" + hash = "sha256-aP0CrNH6UNRMhzgA2NgPwKyZs6xry5aDlZnLgGuHZbs=" + [mod."github.com/yuin/goldmark"] + version = "v1.7.1" + hash = "sha256-3EUgwoZRRs2jNBWSbB0DGNmfBvx7CeAgEwyUdaRaeR4=" + [mod."golang.org/x/net"] + version = "v0.21.0" + hash = "sha256-LfiqMpPtqvW/eLkfx6Ebr5ksqKbQli6uq06c/+XrBsw=" + [mod."golang.org/x/sync"] + version = "v0.3.0" + hash = "sha256-bCJKLvwExhYacH2ZrWlZ38lr1d6oNenNt2m1QqDCs0o=" + [mod."golang.org/x/sys"] + version = "v0.19.0" + hash = "sha256-cmuL31TYLJmDm/fDnI2Sn0wB88cpdOHV1+urorsJWx4=" + [mod."golang.org/x/text"] + version = "v0.14.0" + hash = "sha256-yh3B0tom1RfzQBf1RNmfdNWF1PtiqxV41jW1GVS6JAg=" + [mod."google.golang.org/protobuf"] + version = "v1.30.0" + hash = "sha256-Y07NKhSuJQ2w7F7MAINQyBf+/hdMHOrxwA3B4ljQQKs=" + [mod."gopkg.in/yaml.v2"] + version = "v2.4.0" + hash = "sha256-uVEGglIedjOIGZzHW4YwN1VoRSTK8o0eGZqzd+TNdd0=" diff --git a/nix/scripts.nix b/nix/scripts.nix new file mode 100644 index 0000000..94e4d85 --- /dev/null +++ b/nix/scripts.nix @@ -0,0 +1,49 @@ +{ pkgs ? import { }, ... }: +let + watchFlake = with pkgs; '' + ${watchexec}/bin/watchexec --restart \ + --watch flake.nix \ + --watch flake.lock \ + ''; + image = (builtins.fromTOML (builtins.readFile ../fly.toml)).build.image; + nonDarwinSystem = builtins.replaceStrings [ "darwin" ] [ "linux" ] pkgs.stdenv.system; + attr = "docker-${nonDarwinSystem}"; + sh = (pkgs.lib.optionalString pkgs.stdenv.isDarwin "ssh linux-builder ") + + "sh"; + stream = attr: "nix build --print-out-paths .#${attr} | ${sh}"; +in +with pkgs; [ + (writeShellScriptBin "watch-builder" '' + ${watchFlake} "direnv exec . watchexec -i server.go -i public -r go run ./cmd/build $@" + '') + (writeShellScriptBin "watch-server" '' + ${watchFlake} "direnv exec . watchexec -r go run ./server.go $@" + '') + (writeShellScriptBin "check-licenses" '' + ${go-licenses}/bin/go-licenses check --include_tests ./... --disallowed_types=restricted,forbidden + '') + (writeShellScriptBin "stream" "${stream attr}") + (writeShellScriptBin "stream-fly" "${stream "fly"}") + (writeShellScriptBin "load-locally" '' + ${stream attr} | ${docker-client}/bin/docker load "$@" + '') + (writeShellScriptBin "push-to-registry" '' + if test -z "''${1:-}"; then + cat <<-EOF + USAGE: $0 [skopeo-copy-options] + + Example: $0 docker://some_docker_registry/myimage:tag + + See: https://github.com/containers/skopeo/blob/main/docs/skopeo-copy.1.md + EOF + exit 1 + fi + echo skopeo copy docker-archive:/dev/stdin "$@" + stream-fly | ${gzip}/bin/gzip --fast | ${skopeo}/bin/skopeo copy docker-archive:/dev/stdin "$@" + '') + (writeShellScriptBin "deploy" '' + set -eu + push-to-registry docker://${image} + ${pkgs.flyctl}/bin/flyctl deploy + '') +] -- cgit 1.4.1