feat: add coredns mysql image build and updater
This commit is contained in:
1 parent
c3ab4cfb70
commit
6835e480c1
7 files changed
+195
-1
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
.git
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
name: Build and update CoreDNS MySQL
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: coredns-mysql
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
image:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Check upstream versions
|
||||||
|
if: github.event_name != 'push'
|
||||||
|
run: python3 scripts/update.py
|
||||||
|
- name: Build and test
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
. ./versions.env
|
||||||
|
docker build --pull --build-arg COREDNS_VERSION="$COREDNS_VERSION" --build-arg MYSQL_PLUGIN_REV="$MYSQL_PLUGIN_REV" -f dockerfile -t coredns-mysql:ci .
|
||||||
|
scripts/test-image.sh coredns-mysql:ci "$COREDNS_VERSION"
|
||||||
|
- name: Commit and push updated versions
|
||||||
|
if: github.event_name != 'push'
|
||||||
|
env:
|
||||||
|
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||||
|
GIT_NAME: ${{ vars.GIT_NAME }}
|
||||||
|
GIT_EMAIL: ${{ vars.GIT_EMAIL }}
|
||||||
|
REGISTRY_USER: ${{ vars.REGISTRY_USER }}
|
||||||
|
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if git diff --quiet -- versions.env; then exit 0; fi
|
||||||
|
test -n "$GIT_HOST" && test -n "$GIT_NAME" && test -n "$GIT_EMAIL" && test -n "$REGISTRY_USER" && test -n "$GIT_TOKEN"
|
||||||
|
git config user.name "$GIT_NAME"
|
||||||
|
git config user.email "$GIT_EMAIL"
|
||||||
|
git add versions.env
|
||||||
|
git commit -m 'chore: update upstream versions'
|
||||||
|
askpass=$(mktemp)
|
||||||
|
trap 'rm -f "$askpass"' EXIT
|
||||||
|
printf '%s\n' '#!/bin/sh' 'case "$1" in *Username*) printf "%s\\n" "$REGISTRY_USER" ;; *) printf "%s\\n" "$GIT_TOKEN" ;; esac' > "$askpass"
|
||||||
|
chmod 700 "$askpass"
|
||||||
|
GIT_ASKPASS="$askpass" GIT_TERMINAL_PROMPT=0 git push "https://${GIT_HOST}/${GITHUB_REPOSITORY}.git" HEAD:refs/heads/main
|
||||||
|
- name: Publish image
|
||||||
|
env:
|
||||||
|
GIT_HOST: ${{ vars.GIT_HOST }}
|
||||||
|
REGISTRY_USER: ${{ vars.REGISTRY_USER }}
|
||||||
|
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
test -n "$GIT_HOST" && test -n "$REGISTRY_USER" && test -n "$GIT_TOKEN"
|
||||||
|
. ./versions.env
|
||||||
|
image="${GIT_HOST}/docker/coredns-mysql"
|
||||||
|
printf '%s' "$GIT_TOKEN" | docker login "$GIT_HOST" --username "$REGISTRY_USER" --password-stdin
|
||||||
|
trap 'docker logout "$GIT_HOST" >/dev/null 2>&1 || true' EXIT
|
||||||
|
docker tag coredns-mysql:ci "${image}:${COREDNS_VERSION}"
|
||||||
|
docker tag coredns-mysql:ci "${image}:latest"
|
||||||
|
docker push "${image}:${COREDNS_VERSION}"
|
||||||
|
docker push "${image}:latest"
|
||||||
@@ -1 +1,25 @@
|
|||||||
# coredns-mysql
|
# CoreDNS MySQL
|
||||||
|
|
||||||
|
A CoreDNS container with the [Cloud 66 MySQL plugin](https://github.com/cloud66-oss/coredns_mysql), built from pinned upstream revisions. The image contains the standard CoreDNS plugins as well as `mysql`.
|
||||||
|
|
||||||
|
## Image
|
||||||
|
|
||||||
|
The Gitea Actions workflow builds and tests the image before publishing `git.bjphoster.com/docker/coredns-mysql` with `latest` and the CoreDNS version as tags. Run with a Corefile mounted read-only:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker run --rm -p 53:53/udp -p 53:53/tcp \
|
||||||
|
-v "$PWD/Corefile:/Corefile:ro" \
|
||||||
|
git.bjphoster.com/docker/coredns-mysql:latest -conf /Corefile
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure the plugin and its database according to the [plugin documentation](https://github.com/cloud66-oss/coredns_mysql). Do not store database credentials in the Corefile or repository. The plugin supports DSN environment variables. This image does not initialize a database or change DNS delegation.
|
||||||
|
|
||||||
|
## Updates and CI
|
||||||
|
|
||||||
|
`.gitea/workflows/image.yaml` runs on pushes to `main`, manually, and daily. The scheduled and manual runs check the latest stable CoreDNS release and the plugin's default-branch commit. Changed revisions are built and tested before an update commit is pushed to Gitea and the image is published. The registry tags change only after a successful build and test. A failed build leaves the repository and published images unchanged. The runner needs Docker access and network access to GitHub and Gitea.
|
||||||
|
|
||||||
|
Configure Gitea Actions variables `GIT_HOST`, `GIT_NAME`, `GIT_EMAIL` and `REGISTRY_USER`, and secret `GIT_TOKEN`, with permission to push to this repository and its container registry. The `GIT_TOKEN` is also used for the updater's Git push. Scheduled changes may be reviewed in Git history. Workflow execution and publication begin only after the repository and workflow are pushed and Actions is enabled.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT. See [LICENSE](LICENSE). CoreDNS and the MySQL plugin retain their own upstream licenses.
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
||||||
|
|
||||||
|
FROM golang:1.26-alpine AS build
|
||||||
|
RUN apk add --no-cache git ca-certificates
|
||||||
|
ARG COREDNS_VERSION
|
||||||
|
RUN test -n "$COREDNS_VERSION"
|
||||||
|
RUN git clone --depth 1 --branch "v${COREDNS_VERSION}" https://github.com/coredns/coredns.git /src
|
||||||
|
WORKDIR /src
|
||||||
|
RUN sed -i '/^file:file$/i mysql:github.com/cloud66-oss/coredns_mysql' plugin.cfg
|
||||||
|
ARG MYSQL_PLUGIN_REV
|
||||||
|
RUN test -n "$MYSQL_PLUGIN_REV"
|
||||||
|
RUN go get "github.com/cloud66-oss/coredns_mysql@${MYSQL_PLUGIN_REV}"
|
||||||
|
RUN go generate
|
||||||
|
RUN CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o /coredns .
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
COPY --from=build /coredns /coredns
|
||||||
|
EXPOSE 53 53/udp
|
||||||
|
ENTRYPOINT ["/coredns"]
|
||||||
Executable
+56
@@ -0,0 +1,56 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
image=$1
|
||||||
|
version=$2
|
||||||
|
output=$(docker run --rm "$image" -plugins)
|
||||||
|
printf '%s\n' "$output" | grep -qx 'mysql'
|
||||||
|
docker run --rm "$image" -version | grep -F "CoreDNS-${version}"
|
||||||
|
network="coredns-ci-$$"
|
||||||
|
db="coredns-db-$$"
|
||||||
|
dns="coredns-dns-$$"
|
||||||
|
config=$(mktemp)
|
||||||
|
cleanup() {
|
||||||
|
docker rm -f "$dns" "$db" >/dev/null 2>&1 || true
|
||||||
|
docker network rm "$network" >/dev/null 2>&1 || true
|
||||||
|
rm -f "$config"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT INT TERM
|
||||||
|
docker network create --internal "$network" >/dev/null
|
||||||
|
docker run -d --name "$db" --network "$network" --network-alias database -e MARIADB_ROOT_PASSWORD=test -e MARIADB_DATABASE=coredns mariadb:11 >/dev/null
|
||||||
|
ready=0
|
||||||
|
attempt=0
|
||||||
|
while [ "$attempt" -lt 60 ]; do
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
if docker exec "$db" mariadb -uroot -ptest -e 'SELECT 1' >/dev/null 2>&1; then ready=1; break; fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
[ "$ready" = 1 ] || { docker logs "$db"; exit 1; }
|
||||||
|
docker exec -i "$db" mariadb -uroot -ptest coredns <<'SQL'
|
||||||
|
CREATE TABLE coredns_records (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, zone VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, ttl INT DEFAULT NULL, content TEXT, record_type VARCHAR(255) NOT NULL);
|
||||||
|
INSERT INTO coredns_records (zone, name, ttl, content, record_type) VALUES ('example.test.', 'www', 30, '{"ip":"192.0.2.10"}', 'A');
|
||||||
|
SQL
|
||||||
|
printf '%s\n' '.:1053 {' ' mysql {' ' dsn root:test@tcp(database:3306)/coredns' ' }' ' errors' '}' > "$config"
|
||||||
|
docker create --name "$dns" --network "$network" --network-alias dns "$image" -conf /Corefile >/dev/null
|
||||||
|
docker cp "$config" "$dns:/Corefile"
|
||||||
|
docker start "$dns" >/dev/null
|
||||||
|
docker run --rm --network "$network" python:3.13-slim python -c '
|
||||||
|
import socket, struct, time
|
||||||
|
query = bytes.fromhex("123401000001000000000000") + b"\x03www\x07example\x04test\0" + struct.pack("!HH", 1, 1)
|
||||||
|
for attempt in range(30):
|
||||||
|
try:
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
||||||
|
sock.settimeout(1)
|
||||||
|
sock.sendto(query, ("dns", 1053))
|
||||||
|
response, _ = sock.recvfrom(4096)
|
||||||
|
if response[:2] == b"\x12\x34" and response[3] & 15 == 0 and struct.unpack("!H", response[6:8])[0] and b"\xc0\x00\x02\x0a" in response:
|
||||||
|
print("MySQL-backed DNS query passed")
|
||||||
|
break
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
raise SystemExit("MySQL-backed DNS query failed")
|
||||||
|
'
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import urllib.request
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def fetch(url):
|
||||||
|
request = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "coredns-mysql-updater"})
|
||||||
|
with urllib.request.urlopen(request, timeout=30) as response:
|
||||||
|
return json.load(response)
|
||||||
|
|
||||||
|
|
||||||
|
release = fetch("https://api.github.com/repos/coredns/coredns/releases/latest")
|
||||||
|
plugin = fetch("https://api.github.com/repos/cloud66-oss/coredns_mysql/commits/HEAD")
|
||||||
|
tag = release["tag_name"]
|
||||||
|
revision = plugin["sha"]
|
||||||
|
if not re.fullmatch(r"v[0-9]+\.[0-9]+\.[0-9]+", tag):
|
||||||
|
raise SystemExit(f"Unexpected CoreDNS release: {tag}")
|
||||||
|
if not re.fullmatch(r"[0-9a-f]{40}", revision):
|
||||||
|
raise SystemExit("Unexpected plugin revision")
|
||||||
|
Path("versions.env").write_text(f"COREDNS_VERSION={tag[1:]}\nMYSQL_PLUGIN_REV={revision}\n")
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
COREDNS_VERSION=1.15.0
|
||||||
|
MYSQL_PLUGIN_REV=de52e2924a6f6152d637e3efd08ac27cb9f4d431
|
||||||
Reference in new issue
Block a user