Skip to content

Commit df15770

Browse files
authored
feat: add oci container definitions build with nix (#18)
1 parent bdc4de0 commit df15770

File tree

4 files changed

+250
-5
lines changed

4 files changed

+250
-5
lines changed

.github/workflows/release.yaml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77

88
permissions:
99
contents: write
10+
packages: write
1011

1112
jobs:
1213
release-linux:
@@ -48,3 +49,78 @@ jobs:
4849
args: release --clean --config .goreleaser-darwin.yaml --skip=validate
4950
env:
5051
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52+
53+
release-containers:
54+
runs-on: ubuntu-latest
55+
strategy:
56+
matrix:
57+
variant: [alpine, debian, ubuntu, scratch]
58+
include:
59+
- variant: alpine
60+
is_default: true
61+
- variant: debian
62+
is_default: false
63+
- variant: ubuntu
64+
is_default: false
65+
- variant: scratch
66+
is_default: false
67+
steps:
68+
- uses: actions/checkout@v4
69+
with:
70+
fetch-depth: 0
71+
72+
- uses: DeterminateSystems/nix-installer-action@v17
73+
74+
- uses: nix-community/cache-nix-action@v6
75+
with:
76+
primary-key: nix-${{ runner.os }}-${{ hashFiles('flake.lock') }}
77+
restore-prefixes-first-match: nix-${{ runner.os }}-
78+
79+
- name: login to ghcr
80+
uses: docker/login-action@v3
81+
with:
82+
registry: ghcr.io
83+
username: ${{ github.actor }}
84+
password: ${{ secrets.GITHUB_TOKEN }}
85+
86+
- name: build container
87+
run: nix build ".#snitch-${{ matrix.variant }}" --print-out-paths
88+
89+
- name: load and push container
90+
env:
91+
VERSION: ${{ github.ref_name }}
92+
REPO: ghcr.io/${{ github.repository_owner }}/snitch
93+
VARIANT: ${{ matrix.variant }}
94+
IS_DEFAULT: ${{ matrix.is_default }}
95+
run: |
96+
VERSION="${VERSION#v}"
97+
98+
docker load < result
99+
100+
IMAGE_TAG=$(docker images --format '{{.Repository}}:{{.Tag}}' | grep "snitch:.*-${VARIANT}" | head -1)
101+
102+
if [ -z "$IMAGE_TAG" ]; then
103+
echo "error: could not find loaded image for ${VARIANT}"
104+
exit 1
105+
fi
106+
107+
docker tag "$IMAGE_TAG" "${REPO}:${VERSION}-${VARIANT}"
108+
docker tag "$IMAGE_TAG" "${REPO}:latest-${VARIANT}"
109+
docker push "${REPO}:${VERSION}-${VARIANT}"
110+
docker push "${REPO}:latest-${VARIANT}"
111+
112+
if [ "$IS_DEFAULT" = "true" ]; then
113+
docker tag "$IMAGE_TAG" "${REPO}:${VERSION}"
114+
docker tag "$IMAGE_TAG" "${REPO}:latest"
115+
docker push "${REPO}:${VERSION}"
116+
docker push "${REPO}:latest"
117+
fi
118+
119+
- name: summary
120+
env:
121+
VERSION: ${{ github.ref_name }}
122+
REPO: ghcr.io/${{ github.repository_owner }}/snitch
123+
VARIANT: ${{ matrix.variant }}
124+
run: |
125+
VERSION="${VERSION#v}"
126+
echo "pushed ${REPO}:${VERSION}-${VARIANT}" >> $GITHUB_STEP_SUMMARY

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,47 @@ curl -sSL https://raw.githubusercontent.com/karol-broda/snitch/master/install.sh
107107

108108
> **macos:** the install script automatically removes the quarantine attribute (`com.apple.quarantine`) from the binary to allow it to run without gatekeeper warnings. to disable this, set `KEEP_QUARANTINE=1`.
109109
110+
### docker
111+
112+
pre-built oci images available from github container registry:
113+
114+
```bash
115+
# pull from ghcr.io
116+
docker pull ghcr.io/karol-broda/snitch:latest # alpine (default)
117+
docker pull ghcr.io/karol-broda/snitch:latest-alpine # alpine (~17MB)
118+
docker pull ghcr.io/karol-broda/snitch:latest-scratch # minimal, binary only (~9MB)
119+
docker pull ghcr.io/karol-broda/snitch:latest-debian # debian trixie
120+
docker pull ghcr.io/karol-broda/snitch:latest-ubuntu # ubuntu 24.04
121+
122+
# or use a specific version
123+
docker pull ghcr.io/karol-broda/snitch:0.2.0-alpine
124+
```
125+
126+
alternatively, build locally via nix flake:
127+
128+
```bash
129+
nix build github:karol-broda/snitch#snitch-alpine
130+
docker load < result
131+
```
132+
133+
**running the container:**
134+
135+
```bash
136+
# basic usage - sees host sockets but not process names
137+
docker run --rm --net=host snitch:latest ls
138+
139+
# full info - includes PID, process name, user
140+
docker run --rm --net=host --pid=host --cap-add=SYS_PTRACE snitch:latest ls
141+
```
142+
143+
| flag | purpose |
144+
|------|---------|
145+
| `--net=host` | share host network namespace (required to see host connections) |
146+
| `--pid=host` | share host pid namespace (needed for process info) |
147+
| `--cap-add=SYS_PTRACE` | read process details from `/proc/<pid>` |
148+
149+
> **note:** `CAP_NET_ADMIN` and `CAP_NET_RAW` are not required. snitch reads from `/proc/net/*` which doesn't need special network capabilities.
150+
110151
### binary
111152

112153
download from [releases](https://github.com/karol-broda/snitch/releases):

flake.nix

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,18 @@
8080
in
8181
{
8282
packages = eachSystem (system:
83-
let pkgs = pkgsFor system; in
84-
{
85-
default = mkSnitch pkgs;
83+
let
84+
pkgs = pkgsFor system;
8685
snitch = mkSnitch pkgs;
87-
}
86+
# containers only available on linux
87+
containers = if pkgs.stdenv.isLinux
88+
then import ./nix/containers.nix { inherit pkgs snitch; }
89+
else { };
90+
in
91+
{
92+
default = snitch;
93+
inherit snitch;
94+
} // containers
8895
);
8996

9097
devShells = eachSystem (system:
@@ -94,7 +101,7 @@
94101
in
95102
{
96103
default = pkgs.mkShell {
97-
packages = [ go pkgs.git pkgs.vhs ];
104+
packages = [ go pkgs.git pkgs.vhs pkgs.nix-prefetch-docker ];
98105
env.GOTOOLCHAIN = "local";
99106
shellHook = ''
100107
echo "go toolchain: $(go version)"

nix/containers.nix

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# oci container definitions for snitch
2+
# builds containers based on different base images: alpine, debian trixie, ubuntu
3+
#
4+
# base images are pinned by imageDigest (immutable content hash), not by tag.
5+
# even if the upstream tag gets a new image, builds remain reproducible.
6+
#
7+
# to update base image hashes, run:
8+
# nix-prefetch-docker --image-name alpine --image-tag 3.21
9+
# nix-prefetch-docker --image-name debian --image-tag trixie-slim
10+
# nix-prefetch-docker --image-name ubuntu --image-tag 24.04
11+
#
12+
# this outputs both imageDigest and sha256 values needed below
13+
{ pkgs, snitch }:
14+
let
15+
commonConfig = {
16+
name = "snitch";
17+
tag = snitch.version;
18+
config = {
19+
Entrypoint = [ "${snitch}/bin/snitch" ];
20+
Env = [ "PATH=/bin" ];
21+
Labels = {
22+
"org.opencontainers.image.title" = "snitch";
23+
"org.opencontainers.image.description" = "a friendlier ss/netstat for humans";
24+
"org.opencontainers.image.source" = "https://github.com/karol-broda/snitch";
25+
"org.opencontainers.image.licenses" = "MIT";
26+
};
27+
};
28+
};
29+
30+
# alpine-based container
31+
alpine = pkgs.dockerTools.pullImage {
32+
imageName = "alpine";
33+
imageDigest = "sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c";
34+
sha256 = "sha256-WNbRh44zld3lZtKARhdeWFte9JKgD2bgCuKzETWgGr8=";
35+
finalImageName = "alpine";
36+
finalImageTag = "3.21";
37+
};
38+
39+
# debian trixie (testing) based container
40+
debianTrixie = pkgs.dockerTools.pullImage {
41+
imageName = "debian";
42+
imageDigest = "sha256:e711a7b30ec1261130d0a121050b4ed81d7fb28aeabcf4ea0c7876d4e9f5aca2";
43+
sha256 = "sha256-W/9A7aaPXFCmmg+NTSrFYL+QylsAgfnvkLldyI18tqU=";
44+
finalImageName = "debian";
45+
finalImageTag = "trixie-slim";
46+
};
47+
48+
# ubuntu based container
49+
ubuntu = pkgs.dockerTools.pullImage {
50+
imageName = "ubuntu";
51+
imageDigest = "sha256:c35e29c9450151419d9448b0fd75374fec4fff364a27f176fb458d472dfc9e54";
52+
sha256 = "sha256-0j8xM+mECrBBHv7ZqofiRaeSoOXFBtLYjgnKivQztS0=";
53+
finalImageName = "ubuntu";
54+
finalImageTag = "24.04";
55+
};
56+
57+
# scratch container (minimal, just the snitch binary)
58+
scratch = pkgs.dockerTools.buildImage {
59+
name = "snitch";
60+
tag = "${snitch.version}-scratch";
61+
copyToRoot = pkgs.buildEnv {
62+
name = "snitch-root";
63+
paths = [ snitch ];
64+
pathsToLink = [ "/bin" ];
65+
};
66+
config = commonConfig.config;
67+
};
68+
69+
in
70+
{
71+
snitch-alpine = pkgs.dockerTools.buildImage {
72+
name = "snitch";
73+
tag = "${snitch.version}-alpine";
74+
fromImage = alpine;
75+
copyToRoot = pkgs.buildEnv {
76+
name = "snitch-root";
77+
paths = [ snitch ];
78+
pathsToLink = [ "/bin" ];
79+
};
80+
config = commonConfig.config;
81+
};
82+
83+
snitch-debian = pkgs.dockerTools.buildImage {
84+
name = "snitch";
85+
tag = "${snitch.version}-debian";
86+
fromImage = debianTrixie;
87+
copyToRoot = pkgs.buildEnv {
88+
name = "snitch-root";
89+
paths = [ snitch ];
90+
pathsToLink = [ "/bin" ];
91+
};
92+
config = commonConfig.config;
93+
};
94+
95+
snitch-ubuntu = pkgs.dockerTools.buildImage {
96+
name = "snitch";
97+
tag = "${snitch.version}-ubuntu";
98+
fromImage = ubuntu;
99+
copyToRoot = pkgs.buildEnv {
100+
name = "snitch-root";
101+
paths = [ snitch ];
102+
pathsToLink = [ "/bin" ];
103+
};
104+
config = commonConfig.config;
105+
};
106+
107+
snitch-scratch = scratch;
108+
109+
oci-default = pkgs.dockerTools.buildImage {
110+
name = "snitch";
111+
tag = snitch.version;
112+
fromImage = alpine;
113+
copyToRoot = pkgs.buildEnv {
114+
name = "snitch-root";
115+
paths = [ snitch ];
116+
pathsToLink = [ "/bin" ];
117+
};
118+
config = commonConfig.config;
119+
};
120+
}
121+

0 commit comments

Comments
 (0)