Skip to content

Commit 8148c56

Browse files
authored
Add container builds (#3)
* Add Dockerfile * Add default config files to Docker image * Separate config files and binary * Remove config files from container * Add `.dockerignore` * Remove extra group initialisation * Add example `compose.yaml` * Add documentation to README * Add container builds * Fix README link * Add config for [act](https://nektosact.com/) * Build Docker image with `cargo chef` * Rework build to run on platform matrix * Add caching * Update readme (this is just to test caching...)
1 parent b2a5dc2 commit 8148c56

9 files changed

Lines changed: 278 additions & 2 deletions

File tree

.actrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
--secret GITHUB_TOKEN
2+
--artifact-server-path ./.artifacts
3+
--matrix platform:amd64
4+
--eventpath ./act_event.json
5+
--platform ubuntu-24.04=catthehacker/ubuntu:act-latest

.dockerignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Various config files
2+
.github/
3+
.gitignore
4+
Makefile.toml
5+
rustfmt.toml
6+
7+
# Builds
8+
target/
9+
.artifacts/
10+
11+
# Documentation
12+
compose.example.yaml
13+
LICENSE
14+
README.md
15+
16+
# Yes, really!
17+
Dockerfile
18+
.dockerignore
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
name: Build binaries
2+
13
on:
24
release:
35
types: [ created ]
46

57
jobs:
6-
release:
8+
build:
79
env:
810
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
911

.github/workflows/build-image.yml

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
name: Build container images
2+
3+
on:
4+
push:
5+
branches: ["master"]
6+
tags: ["*"]
7+
pull_request:
8+
branches: ["master"]
9+
workflow_dispatch:
10+
11+
env:
12+
REGISTRY: ghcr.io
13+
14+
jobs:
15+
meta:
16+
name: Set metadata
17+
runs-on: ubuntu-24.04
18+
outputs:
19+
image_name: ${{ steps.meta.outputs.image_name }}
20+
21+
steps:
22+
- name: Set metadata
23+
id: meta
24+
env:
25+
registry: ${{ env.REGISTRY }}
26+
owner: ${{ github.repository_owner }}
27+
repo: ${{ github.event.repository.name }}
28+
run: |
29+
echo "image_name=${registry,,}/${owner,,}/${repo,,}" >> "$GITHUB_OUTPUT"
30+
31+
build:
32+
needs:
33+
- meta
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
include:
38+
- platform: amd64
39+
os: linux
40+
runner: ubuntu-24.04
41+
- platform: arm64
42+
os: linux
43+
runner: ubuntu-24.04-arm
44+
runs-on: ${{ matrix.runner }}
45+
steps:
46+
- name: Checkout repository
47+
uses: actions/checkout@v6.0.0
48+
49+
- name: Set up Docker Buildx
50+
id: setup-buildx
51+
uses: docker/setup-buildx-action@v3.11.1
52+
53+
- name: Log in to registry
54+
uses: docker/login-action@v3.6.0
55+
with:
56+
registry: ${{ env.REGISTRY }}
57+
username: ${{ github.actor }}
58+
password: ${{ secrets.GITHUB_TOKEN }}
59+
60+
- name: Get Docker metadata
61+
id: meta
62+
uses: docker/metadata-action@v5.10.0
63+
with:
64+
images: ${{ needs.meta.outputs.image_name }}
65+
66+
- name: Build and push by digest
67+
id: build
68+
uses: docker/build-push-action@v6.18.0
69+
with:
70+
context: .
71+
platforms: ${{ matrix.os }}/${{ matrix.platform }}
72+
labels: ${{ steps.meta.outputs.labels }}
73+
tags: ${{ needs.meta.outputs.image_name }}
74+
outputs: type=registry,push-by-digest=true,name-canonical=true
75+
cache-from: type=gha,scope=${{ matrix.platform }}-${{ github.ref_name }}
76+
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}-${{ github.ref_name }}
77+
78+
- name: Export digest
79+
run: |
80+
mkdir -p ${{ runner.temp }}/digests
81+
digest="${{ steps.build.outputs.digest }}"
82+
touch "${{ runner.temp }}/digests/${digest#sha256:}"
83+
84+
- name: Upload digest
85+
uses: actions/upload-artifact@v5.0.0
86+
with:
87+
name: digests-${{ matrix.os }}-${{ matrix.platform }}
88+
path: ${{ runner.temp }}/digests/*
89+
if-no-files-found: error
90+
retention-days: 1
91+
92+
merge:
93+
needs:
94+
- meta
95+
- build
96+
runs-on: ubuntu-24.04
97+
98+
steps:
99+
- name: Download digests
100+
uses: actions/download-artifact@v6.0.0
101+
with:
102+
path: ${{ runner.temp }}/digests
103+
pattern: digests-*
104+
merge-multiple: true
105+
106+
- name: Log in to registry
107+
uses: docker/login-action@v3.6.0
108+
with:
109+
registry: ${{ env.REGISTRY }}
110+
username: ${{ github.actor }}
111+
password: ${{ secrets.GITHUB_TOKEN }}
112+
113+
- name: Set up Docker Buildx
114+
uses: docker/setup-buildx-action@v3.11.1
115+
116+
- name: Get Docker metadata
117+
id: meta
118+
uses: docker/metadata-action@v5.10.0
119+
with:
120+
images: ${{ needs.meta.outputs.image_name }}
121+
tags: |
122+
type=ref,event=branch
123+
type=ref,event=pr
124+
type=semver,pattern={{version}}
125+
126+
- name: Create manifest list and push
127+
working-directory: ${{ runner.temp }}/digests
128+
run: |
129+
docker buildx imagetools create \
130+
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
131+
$(printf '${{ needs.meta.outputs.image_name }}@sha256:%s ' *)
132+
133+
- name: Inspect image
134+
run: |
135+
docker buildx imagetools inspect ${{ needs.meta.outputs.image_name }}:${{ steps.meta.outputs.version }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
.idea/
33
.vscode/
44
target/
5+
.artifacts/

Dockerfile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
ARG RUST_IMAGE_VERSION="1.91.1-alpine3.20"
2+
ARG ALPINE_IMAGE_VERSION="3.22.2"
3+
ARG USER="shay"
4+
ARG UID="1000"
5+
6+
####################################################################################################
7+
8+
FROM rust:${RUST_IMAGE_VERSION} AS build_base
9+
WORKDIR /build
10+
11+
RUN apk update && apk add g++
12+
RUN cargo +nightly install cargo-chef --locked --version 0.1.73
13+
14+
####################################################################################################
15+
16+
FROM build_base AS build_plan
17+
COPY . .
18+
RUN cargo +nightly chef prepare --recipe-path recipe.json
19+
20+
####################################################################################################
21+
22+
FROM build_base AS build
23+
24+
COPY --from=build_plan /build/recipe.json recipe.json
25+
RUN cargo +nightly chef cook --release --recipe-path recipe.json
26+
27+
COPY . .
28+
RUN cargo +nightly build --release --locked --bin shaysbot
29+
30+
####################################################################################################
31+
32+
FROM alpine:${ALPINE_IMAGE_VERSION} AS run
33+
ARG USER
34+
ARG UID
35+
ARG GID
36+
WORKDIR /config
37+
38+
RUN <<EOF
39+
adduser \
40+
--disabled-password \
41+
--no-create-home \
42+
--uid "${UID}" \
43+
"${USER}"
44+
chown -R "${USER}":"${USER}" /config
45+
EOF
46+
USER ${USER}
47+
48+
COPY --from=build /build/target/release/shaysbot /usr/local/bin/shaysbot
49+
ENTRYPOINT [ "shaysbot" ]

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
My personal Minecraft bot written in Rust built with [Azalea].
1414
Primarily designed to be a pearl bot, allowing for quick travel to different locations with multiple accounts.
15-
Also featuring a Discord bot, an HTTP API for local integrations, and support for [No Chat Reports] encryption.
15+
Also featuring a Discord bot, an HTTP API for local integrations, a Docker image, and support for [No Chat Reports] encryption.
1616

1717
## How to use
1818

@@ -42,6 +42,17 @@ The first is the log level of the bot, the second is of dependencies.
4242

4343
Compiled with [GitHub Actions](.github/workflows/release.yml) using the [**Debug**](#cargo-profiles) profile.
4444

45+
### Docker
46+
Pull from the image `ghcr.io/ShayBox/ShaysBot`. Available tags are listed
47+
[here](https://github.com/ShayBox/ShaysBot/pkgs/container/shaysbot/versions).
48+
49+
All configuration files are in the container's working directory, `/config`. If using a bind mount
50+
for this directory, make sure `config` mount point on the host has the proper permissions and
51+
ownership set for the application to be able to access it inside the container.
52+
53+
For an example `compose.yaml` file for use with Docker Compose, see
54+
[`compose.example.yaml`](./compose.example.yaml).
55+
4556
### Install or Develop Locally
4657

4758
Prerequisites:

act_event.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"repository": {
3+
"name": "ShaysBot"
4+
}
5+
}

compose.example.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
services:
2+
bot:
3+
restart: unless-stopped
4+
image: shaysbot:latest # replace with a versioned tag!
5+
volumes:
6+
- ./config:/config # create this directory first!
7+
8+
9+
# ZenithProxy (below) is optional -- uncomment to enable it
10+
11+
# proxy:
12+
# image: ghcr.io/rfresh2/zenithproxy:latest # replace with a versioned tag!
13+
# ports:
14+
# - '25565:25565'
15+
# environment:
16+
# # The port that ZenithProxy will be connectable on.
17+
# ZENITH_PORT: "25565"
18+
19+
# # The host that ZenithProxy will be bound to. This can be an IP address (eg. 203.0.113.67), a
20+
# # hostname (eg. mc-proxy) or a FQDN (eg. mc.example.com)
21+
# ZENITH_IP: "localhost"
22+
23+
# # The version of Minecraft Zenith will run.
24+
# # Latest version is usually supported, others are deprecated.
25+
# ZENITH_MC_VERSION: "1.21.4"
26+
27+
# # The authorization token granted by Discord when configuring a Bot user.
28+
# ZENITH_DISCORD_TOKEN: "<change me>"
29+
30+
# # The ID of the Discord role that should allow users to interact ZenithProxy.
31+
# ZENITH_DISCORD_ROLE_ID: "<change me>"
32+
33+
# # The ID of the Discord channel in which ZenithProxy will look for commands, also referred to
34+
# # as the "Management channel".
35+
# ZENITH_DISCORD_CHANNEL_ID: "<change me>"
36+
37+
# # The ChatRelay is a live feed of chat messages and/or connection messages from the server to
38+
# # a Discord channel. To enable it, set this variable to the ID of the channel you want to use
39+
# # for ChatRelay. This can't be the same as the Management channel.
40+
# # ZENITH_DISCORD_CHAT_RELAY_CHANNEL: ""
41+
42+
# # Completely disable ZenithProxy's Discord integration. As Discord is the main way most users
43+
# # will interact with ZenithProxy, you probably want to leave this set to `false`.
44+
# # ZENITH_DISCORD_DISABLED: "false"
45+
46+
# # On Linux, ZenithProxy can be run as a specially optimized binary. On other platforms, it
47+
# # must be run directly via the JVM. The former method is better, and will be chosen
48+
# # automatically by ZenithProxy if the environment supports it. You probably shouldn't override
49+
# # this unless you know what you're doing.
50+
# # ZENITH_PLATFORM: "linux"

0 commit comments

Comments
 (0)