[comment] switch to new workflow

This commit is contained in:
ElevenNotes
2025-03-20 11:53:31 +01:00
parent e0c98e0059
commit a05d0f6ebd
22 changed files with 567 additions and 432 deletions

View File

@@ -1,5 +1,7 @@
# default
.git*
*.md
LICENSE
maintain/
project*
LICENSE
*.md
img/
node_modules/

4
.gitattributes vendored
View File

@@ -1,2 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
* text=auto
*.sh eol=lf

328
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,328 @@
name: docker
run-name: ${{ inputs.run-name }}
on:
workflow_dispatch:
inputs:
run-name:
description: 'set run-name for workflow (multiple calls)'
type: string
required: false
default: 'docker'
release:
description: 'set WORKFLOW_GITHUB_RELEASE'
required: false
default: 'false'
readme:
description: 'set WORKFLOW_GITHUB_README'
required: false
default: 'false'
image:
description: 'set IMAGE'
required: false
uid:
description: 'set IMAGE_UID'
required: false
gid:
description: 'set IMAGE_GID'
required: false
semverprefix:
description: 'prefix for semver tags'
required: false
semversuffix:
description: 'suffix for semver tags'
required: false
jobs:
docker:
runs-on: ubuntu-22.04
services:
registry:
image: registry:2
ports:
- 5000:5000
permissions:
actions: read
contents: write
packages: write
security-events: write
steps:
- name: init / checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
ref: ${{ github.ref_name }}
fetch-depth: 0
- name: init / setup environment
uses: actions/github-script@62c3794a3eb6788d9a2a72b219504732c0c9a298
with:
script: |
const { existsSync, readFileSync } = require('node:fs');
const { resolve } = require('node:path');
const inputs = `${{ toJSON(github.event.inputs) }}`;
const opt = {input:{}, dot:{}};
try{
if(inputs.length > 0){
opt.input = JSON.parse(inputs);
}
}catch(e){
core.warning('could not parse github.event.inputs');
}
try{
const path = resolve('.json');
if(existsSync(path)){
try{
opt.dot = JSON.parse(readFileSync(path).toString());
}catch(e){
throw new Error('could not parse .json');
}
}else{
throw new Error('.json does not exist');
}
}catch(e){
core.setFailed(e);
}
const docker = {
image:{
name:(opt.input?.image || opt.dot.image),
arch:(opt.dot.arch || 'linux/amd64,linux/arm64'),
prefix:((opt.input?.semverprefix) ? `${opt.input?.semverprefix}-` : ''),
suffix:((opt.input?.semversuffix) ? `-${opt.input?.semversuffix}` : ''),
description:(opt.dot?.readme?.description || ''),
tags:[],
},
app:{
image:opt.dot.image,
name:opt.dot.name,
version:opt.dot.semver.version,
root:opt.dot.root,
UID:(opt.input?.uid || 1000),
GID:(opt.input?.gid || 1000),
no_cache:new Date().getTime(),
},
cache:{
registry:'localhost:5000/',
}
};
docker.cache.name = `${docker.image.name}:${docker.image.prefix}buildcache${docker.image.suffix}`;
docker.cache.grype = `${docker.cache.registry}${docker.image.name}:${docker.image.prefix}grype${docker.image.suffix}`;
docker.app.prefix = docker.image.prefix;
docker.app.suffix = docker.image.suffix;
// setup tags
const semver = opt.dot.semver.version.split('.');
docker.image.tags.push(`${context.sha.substring(0,7)}`);
if(Array.isArray(semver)){
if(semver.length >= 1) docker.image.tags.push(`${semver[0]}`);
if(semver.length >= 2) docker.image.tags.push(`${semver[0]}.${semver[1]}`);
if(semver.length >= 3) docker.image.tags.push(`${semver[0]}.${semver[1]}.${semver[2]}`);
}
if(opt.dot.semver?.stable && new RegExp(opt.dot.semver.stable, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('stable');
if(opt.dot.semver?.latest && new RegExp(opt.dot.semver.latest, 'ig').test(docker.image.tags.join(','))) docker.image.tags.push('latest');
for(let i=0; i<docker.image.tags.length; i++){
docker.image.tags[i] = `${docker.image.name}:${docker.image.prefix}${docker.image.tags[i]}${docker.image.suffix}`;
}
// setup build arguments
const arguments = [];
for(const argument in docker.app){
arguments.push(`APP_${argument.toUpperCase()}=${docker.app[argument]}`);
}
// export to environment
core.exportVariable('DOCKER_CACHE_REGISTRY', docker.cache.registry);
core.exportVariable('DOCKER_CACHE_NAME', docker.cache.name);
core.exportVariable('DOCKER_CACHE_GRYPE', docker.cache.grype);
core.exportVariable('DOCKER_IMAGE_NAME', docker.image.name);
core.exportVariable('DOCKER_IMAGE_ARCH', docker.image.arch);
core.exportVariable('DOCKER_IMAGE_TAGS', docker.image.tags.join(','));
core.exportVariable('DOCKER_IMAGE_DESCRIPTION', docker.image.description);
core.exportVariable('DOCKER_IMAGE_ARGUMENTS', arguments.join("\r\n"));
core.exportVariable('WORKFLOW_CREATE_RELEASE', (opt.input?.release || true));
core.exportVariable('WORKFLOW_CREATE_README', (opt.input?.readme || true));
core.exportVariable('WORKFLOW_GRYPE_FAIL_ON_SEVERITY', (opt.json?.grpye?.fail || true));
core.exportVariable('WORKFLOW_GRYPE_SEVERITY_CUTOFF', (opt.json?.grpye?.severity || 'high'));
# DOCKER
- name: docker / login to hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
with:
username: 11notes
password: ${{ secrets.DOCKER_TOKEN }}
- name: docker / setup qemu
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a
- name: docker / setup buildx
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5
with:
driver-opts: network=host
- name: docker / build & push & tag grype
id: docker-build
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d
with:
context: .
file: arch.dockerfile
push: true
platforms: ${{ env.DOCKER_IMAGE_ARCH }}
cache-from: type=registry,ref=${{ env.DOCKER_CACHE_NAME }}
cache-to: type=registry,ref=${{ env.DOCKER_CACHE_REGISTRY }}${{ env.DOCKER_CACHE_NAME }},mode=max,compression=zstd,force-compression=true
build-args: |
${{ env.DOCKER_IMAGE_ARGUMENTS }}
tags: |
${{ env.DOCKER_CACHE_GRYPE }}
- name: grype / scan
id: grype
uses: anchore/scan-action@abae793926ec39a78ab18002bc7fc45bbbd94342
with:
image: ${{ env.DOCKER_CACHE_GRYPE }}
fail-build: ${{ env.WORKFLOW_GRYPE_FAIL_ON_SEVERITY }}
severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }}
output-format: 'sarif'
by-cve: true
cache-db: true
- name: grype / fail
if: failure() || steps.grype.outcome == 'failure'
uses: anchore/scan-action@abae793926ec39a78ab18002bc7fc45bbbd94342
with:
image: ${{ env.DOCKER_CACHE_GRYPE }}
fail-build: false
severity-cutoff: ${{ env.WORKFLOW_GRYPE_SEVERITY_CUTOFF }}
output-format: 'table'
by-cve: true
cache-db: true
- name: docker / build & push
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d
with:
context: .
file: arch.dockerfile
push: true
sbom: true
provenance: mode=max
platforms: ${{ env.DOCKER_IMAGE_ARCH }}
cache-from: type=registry,ref=${{ env.DOCKER_CACHE_REGISTRY }}${{ env.DOCKER_CACHE_NAME }}
cache-to: type=registry,ref=${{ env.DOCKER_CACHE_NAME }},mode=max,compression=zstd,force-compression=true
build-args: |
${{ env.DOCKER_IMAGE_ARGUMENTS }}
tags: |
${{ env.DOCKER_IMAGE_TAGS }}
# RELEASE
- name: github / release / log
continue-on-error: true
id: git-log
run: |
LOCAL_LAST_TAG=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`)
echo "using last tag: ${LOCAL_LAST_TAG}"
LOCAL_COMMITS=$(git log ${LOCAL_LAST_TAG}..HEAD --oneline)
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
echo "commits<<${EOF}" >> ${GITHUB_OUTPUT}
echo "${LOCAL_COMMITS}" >> ${GITHUB_OUTPUT}
echo "${EOF}" >> ${GITHUB_OUTPUT}
- name: github / release / markdown
if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-log.outcome == 'success'
id: git-release
uses: 11notes/action-docker-release@v1
with:
git_log: ${{ steps.git-log.outputs.commits }}
- name: github / release / create
if: env.WORKFLOW_CREATE_RELEASE == 'true' && steps.git-release.outcome == 'success'
uses: actions/create-release@4c11c9fe1dcd9636620a16455165783b20fc7ea0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: ${{ steps.git-release.outputs.release }}
draft: false
prerelease: false
# README
- name: github / checkout master
continue-on-error: true
run: |
git checkout master
- name: github / create README.md
id: github-readme
continue-on-error: true
if: env.WORKFLOW_CREATE_README == 'true' && steps.docker-build.outcome == 'success'
uses: 11notes/action-docker-readme@v1
with:
sarif_file: ${{ steps.grype.outputs.sarif }}
build_output_metadata: ${{ steps.docker-build.outputs.metadata }}
- name: github / commit & push
continue-on-error: true
if: steps.github-readme.outcome == 'success' && hashFiles('README.md') != ''
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add README.md
if [ -f compose.yaml ]; then
git add compose.yaml
fi
git commit -m "auto update README.md"
git push
- name: docker / push README.md to docker hub
continue-on-error: true
if: steps.github-readme.outcome == 'success' && hashFiles('README.md') != ''
uses: christian-korneck/update-container-description-action@d36005551adeaba9698d8d67a296bd16fa91f8e8
env:
DOCKER_USER: 11notes
DOCKER_PASS: ${{ secrets.DOCKER_TOKEN }}
with:
destination_container_repo: ${{ env.DOCKER_IMAGE_NAME }}
provider: dockerhub
short_description: ${{ env.DOCKER_IMAGE_DESCRIPTION }}
readme_file: 'README.md'
# REPOSITORY SETTINGS
- name: github / update description and set repo defaults
run: |
curl --request PATCH \
--url https://api.github.com/repos/${{ github.repository }} \
--header 'authorization: Bearer ${{ secrets.REPOSITORY_TOKEN }}' \
--header 'content-type: application/json' \
--data '{
"description":"${{ env.DOCKER_IMAGE_DESCRIPTION }}",
"homepage":"",
"has_issues":true,
"has_discussions":true,
"has_projects":false,
"has_wiki":false
}' \
--fail

View File

@@ -1,32 +0,0 @@
name: create release notes
on:
push:
tags:
- "*"
- "!amd64*"
- "!arm64*"
permissions:
contents: write
jobs:
release:
name: release
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: ./
steps:
- name: create release notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
set -ex; \
wget -O ./RELEASE.md https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/refs/heads/master/RELEASE.md; \
gh release create "$tag" \
--repo="$GITHUB_REPOSITORY" \
--title="${tag#v}" \
-F ./RELEASE.md

15
.github/workflows/tags.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: tags
on:
push:
tags:
- 'v*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: build docker image
uses: the-actions-org/workflow-dispatch@3133c5d135c7dbe4be4f9793872b6ef331b53bc7
with:
workflow: docker.yml
token: "${{ secrets.REPOSITORY_TOKEN }}"
inputs: '{ "release":"true", "readme":"true" }'

4
.gitignore vendored
View File

@@ -1,3 +1,3 @@
# default
maintain/
project*
build
node_modules/

21
.json Normal file
View File

@@ -0,0 +1,21 @@
{
"image":"11notes/bind",
"name":"bind",
"root":"/bind",
"semver":{
"version":"9.18.35",
"stable":"9.18.35",
"latest":"9.18.35"
},
"readme":{
"description":"High performance bind with default operating modes",
"parent":{
"image":"11notes/alpine:stable"
},
"built":{
"bind":"https://gitlab.isc.org/isc-projects/bind9"
}
}
}

View File

@@ -1,84 +0,0 @@
![Banner](https://github.com/11notes/defaults/blob/main/static/img/banner.png?raw=true)
# 🏔️ Alpine - BIND
[<img src="https://img.shields.io/badge/github-source-blue?logo=github">](https://github.com/11notes/docker-bind/tree/9.18.31) ![size](https://img.shields.io/docker/image-size/11notes/bind/9.18.31?color=0eb305) ![version](https://img.shields.io/docker/v/11notes/bind/9.18.31?color=eb7a09) ![pulls](https://img.shields.io/docker/pulls/11notes/bind?color=2b75d6)
**High performance bind with default operating modes**
# SYNOPSIS
**What can I do with this?** This image will run BIND9 DNS server precompiled for large installations and maximum performance. It also offers three operating modes: Master, Slave and Resolver set via **command: ["mode"]**.
# Master
If run as master, set the IPs of the slaves via *BIND_SLAVES*. Bind will operate with catalog zones for all slaves. You can add new zones via the *addzone* script that requires the zone name and the IP of at least one NS (slave). You can then use nsupdate to update the master with new records and all changes are populates to all slaves automatically. Add a new zone like this:
```shell
docker exec master addzone contoso.com 10.255.53.52
```
It will automatically create a default zone and populate it as well as add a random key for managing the zone via nsupdate or via the dynamically created root key at startup (check /bind/etc/keys.conf for generated keys). Checkout **compose.authoritative.yaml** for an example.
# Slave
If run as slave, make sure you set the *BIND_MASTERS* IPs so they will pickup all changes automatically. The slave enables recursion, so make sure you have a resolver present to resolve queries not handles by the slave. The slave will respond to all IPs on RFC1918 by default. You can setup your own config as well. You can run as many slaves as you like.
# Resolver
If run as a resolver, it will cache all results and use the root zone NS to create its own cache database for all records requested. Make sure the resolver has internet access. The resolver will accept all connections from any RFC1918 address. Checkout **compose.resolver.yaml** for an example.
# VOLUMES
* **/bind/etc** - Directory of named.conf
* **/bind/var** - Directory of zone data
# COMPOSE
```yaml
services:
bind:
image: "11notes/bind:9.18.31"
container_name: "bind"
environment:
TZ: "Europe/Zurich"
volumes:
- "etc:/bind/etc"
- "var:/bind/var"
ports:
- "53:53/udp"
- "53:53/tcp"
- "8053:8053/tcp"
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always
volumes:
etc:
var:
```
# DEFAULT SETTINGS
| Parameter | Value | Description |
| --- | --- | --- |
| `user` | docker | user docker |
| `uid` | 1000 | user id 1000 |
| `gid` | 1000 | group id 1000 |
| `home` | /bind | home directory of user docker |
# ENVIRONMENT
| Parameter | Value | Default |
| --- | --- | --- |
| `TZ` | [Time Zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | |
| `DEBUG` | Show debug information | |
| `BIND_SLAVES` | IPs of bind slaves if using authoritative master (add ;) | |
| `BIND_MASTERS` | IPs of bind master if using authoritative slave (add ;) | |
# SOURCE
* [11notes/bind:9.18.31](https://github.com/11notes/docker-bind/tree/9.18.31)
# PARENT IMAGE
* [11notes/alpine:stable](https://hub.docker.com/r/11notes/alpine)
# BUILT WITH
* [bind](https://www.isc.org/downloads/bind)
* [alpine](https://alpinelinux.org)
# TIPS
* Use a reverse proxy like Traefik, Nginx to terminate TLS with a valid certificate
* Use Lets Encrypt certificates to protect your SSL endpoints
# ElevenNotes<sup>™️</sup>
This image is provided to you at your own risk. Always make backups before updating an image to a different version. Check the [RELEASE.md](https://github.com/11notes/docker-bind/blob/9.18.31/RELEASE.md) for breaking changes. You can find all my repositories on [github](https://github.com/11notes).

View File

@@ -1,2 +0,0 @@
### New Features
* Operating modus: Master, Slave and Resolver

View File

@@ -1,134 +0,0 @@
# :: Util
FROM alpine as util
RUN set -ex; \
apk add --no-cache \
git; \
git clone https://github.com/11notes/util.git;
# :: Build
FROM 11notes/alpine:stable as build
ARG BUILD_VERSION=9.18.31
ARG BUILD_DIR=/bind9
USER root
RUN set -ex; \
apk add --no-cache --update \
alpine-sdk \
openssl-dev \
libuv-dev \
curl \
wget \
unzip \
build-base \
linux-headers \
make \
cmake \
autoconf \
automake \
libtool \
bash \
userspace-rcu \
fstrm-dev \
jemalloc-dev \
json-c-dev \
libidn2-dev \
krb5-dev \
libcap-dev \
libuv-dev \
libxml2-dev \
linux-headers \
nghttp2-dev \
openldap-dev \
openssl-dev>3 \
perl \
protobuf-c-dev \
g++ \
git;
RUN set -ex; \
git clone https://gitlab.isc.org/isc-projects/bind9.git -b v${BUILD_VERSION};
RUN set -ex; \
cd ${BUILD_DIR}; \
autoreconf --install; \
./configure \
--prefix=/opt/bind \
--sysconfdir=/bind/etc \
--localstatedir=/var \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--with-tuning=large \
--with-gssapi \
--with-libxml2 \
--with-json-c \
--with-openssl \
--with-jemalloc \
--with-libidn2 \
--enable-dnstap \
--enable-largefile \
--enable-linux-caps \
--enable-shared \
--disable-static \
--enable-full-report;
RUN set -ex; \
cd ${BUILD_DIR}; \
make -j$(nproc);
RUN set -ex; \
cd ${BUILD_DIR}; \
make install;
# :: Header
FROM 11notes/alpine:stable
COPY --from=util /util/docker /usr/local/bin
COPY --from=build /opt/bind /opt/bind
ENV APP_NAME="bind"
ENV APP_VERSION=9.18.31
ENV APP_ROOT=/bind
# :: Run
USER root
# :: prepare
RUN set -ex; \
mkdir -p \
${APP_ROOT}/etc \
${APP_ROOT}/var \
/var/run/named;
# :: install
RUN set -ex; \
apk --no-cache --update add \
json-c \
libuv \
libxml2 \
protobuf-c \
fstrm \
libcap \
jemalloc \
krb5;
# :: copy root filesystem
COPY ./rootfs /
RUN set -ex; \
chmod +x -R /usr/local/bin
# :: change permissions
RUN set -ex; \
usermod -d ${APP_ROOT} docker; \
chown -R 1000:1000 \
${APP_ROOT} \
/var/run/named;
# :: Volumes
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]
# :: Monitor
HEALTHCHECK --interval=5s --timeout=3s CMD /usr/local/bin/healthcheck.sh || exit 1
# :: Start
USER docker
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

132
arch.dockerfile Normal file
View File

@@ -0,0 +1,132 @@
# :: Util
FROM 11notes/util AS util
# :: Build / bind
FROM alpine/git AS build
ARG APP_VERSION
ENV BUILD_ROOT=/git/bind9
RUN set -ex; \
apk add --no-cache --update \
alpine-sdk \
openssl-dev \
libuv-dev \
curl \
wget \
unzip \
build-base \
linux-headers \
make \
cmake \
autoconf \
automake \
libtool \
bash \
userspace-rcu \
fstrm-dev \
jemalloc-dev \
json-c-dev \
libidn2-dev \
krb5-dev \
libcap-dev \
libuv-dev \
libxml2-dev \
linux-headers \
nghttp2-dev \
openldap-dev \
openssl-dev>3 \
perl \
protobuf-c-dev \
g++;
RUN set -ex; \
git clone https://gitlab.isc.org/isc-projects/bind9.git -b v${APP_VERSION};
RUN set -ex; \
cd ${BUILD_ROOT}; \
autoreconf --install; \
./configure \
--prefix=/opt/bind \
--sysconfdir=/bind/etc \
--localstatedir=/var \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--with-tuning=large \
--with-gssapi \
--with-libxml2 \
--with-json-c \
--with-openssl \
--with-jemalloc \
--with-libidn2 \
--enable-dnstap \
--enable-largefile \
--enable-linux-caps \
--enable-shared \
--disable-static \
--enable-full-report;
RUN set -ex; \
cd ${BUILD_ROOT}; \
make -j$(nproc);
RUN set -ex; \
cd ${BUILD_ROOT}; \
make install;
# :: Header
FROM 11notes/alpine:stable
# :: arguments
ARG TARGETARCH
ARG APP_IMAGE
ARG APP_NAME
ARG APP_VERSION
ARG APP_ROOT
ARG APP_UID
ARG APP_GID
# :: environment
ENV APP_IMAGE=${APP_IMAGE}
ENV APP_NAME=${APP_NAME}
ENV APP_VERSION=${APP_VERSION}
ENV APP_ROOT=${APP_ROOT}
# :: multi-stage
COPY --from=util /usr/local/bin/ /usr/local/bin
COPY --from=build /opt/bind /opt/bind
# :: Run
USER root
RUN eleven printenv;
# :: install application
RUN set -ex; \
eleven mkdir ${APP_ROOT}/{etc,var}; \
mkdir -p /var/run/named;
RUN set -ex; \
apk --no-cache --update add \
json-c \
libuv \
libxml2 \
protobuf-c \
fstrm \
libcap \
jemalloc \
krb5;
# :: copy filesystem changes and set correct permissions
COPY ./rootfs /
RUN set -ex; \
chmod +x -R /usr/local/bin; \
chown -R 1000:1000 \
${APP_ROOT} \
/var/run/named;
# :: Volumes
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]
# :: Monitor
HEALTHCHECK --interval=5s --timeout=2s CMD dig +time=2 +tries=1 . NS @localhost || exit 1
# :: Start
USER docker

View File

@@ -1,139 +0,0 @@
# :: QEMU
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
# :: Util
FROM alpine as util
RUN set -ex; \
apk add --no-cache \
git; \
git clone https://github.com/11notes/util.git;
# :: Build
FROM --platform=linux/arm64 11notes/alpine:stable as build
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
ARG BUILD_VERSION=9.18.31
ARG BUILD_DIR=/bind9
USER root
RUN set -ex; \
apk add --no-cache --update \
alpine-sdk \
openssl-dev \
libuv-dev \
curl \
wget \
unzip \
build-base \
linux-headers \
make \
cmake \
autoconf \
automake \
libtool \
bash \
userspace-rcu \
fstrm-dev \
jemalloc-dev \
json-c-dev \
libidn2-dev \
krb5-dev \
libcap-dev \
libuv-dev \
libxml2-dev \
linux-headers \
nghttp2-dev \
openldap-dev \
openssl-dev>3 \
perl \
protobuf-c-dev \
g++ \
git;
RUN set -ex; \
git clone https://gitlab.isc.org/isc-projects/bind9.git -b v${BUILD_VERSION};
RUN set -ex; \
cd ${BUILD_DIR}; \
autoreconf --install; \
./configure \
--prefix=/opt/bind \
--sysconfdir=/bind/etc \
--localstatedir=/var \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--with-tuning=large \
--with-gssapi \
--with-libxml2 \
--with-json-c \
--with-openssl \
--with-jemalloc \
--with-libidn2 \
--enable-dnstap \
--enable-largefile \
--enable-linux-caps \
--enable-shared \
--disable-static \
--enable-full-report;
RUN set -ex; \
cd ${BUILD_DIR}; \
make -j$(nproc);
RUN set -ex; \
cd ${BUILD_DIR}; \
make install;
# :: Header
FROM --platform=linux/arm64 11notes/alpine:stable
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
COPY --from=util /util/docker /usr/local/bin
COPY --from=build /opt/bind /opt/bind
ENV APP_NAME="bind"
ENV APP_VERSION=9.18.31
ENV APP_ROOT=/bind
# :: Run
USER root
# :: prepare
RUN set -ex; \
mkdir -p \
${APP_ROOT}/etc \
${APP_ROOT}/var \
/var/run/named;
# :: install
RUN set -ex; \
apk --no-cache --update add \
json-c \
libuv \
libxml2 \
protobuf-c \
fstrm \
libcap \
jemalloc \
krb5;
# :: copy root filesystem
COPY ./rootfs /
RUN set -ex; \
chmod +x -R /usr/local/bin
# :: change permissions
RUN set -ex; \
usermod -d ${APP_ROOT} docker; \
chown -R 1000:1000 \
${APP_ROOT} \
/var/run/named;
# :: Volumes
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]
# :: Monitor
HEALTHCHECK --interval=5s --timeout=3s CMD /usr/local/bin/healthcheck.sh || exit 1
# :: Start
USER docker
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

View File

@@ -41,9 +41,11 @@ services:
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always
volumes:
etc:
var:
networks:
macvlan:
driver: macvlan

View File

@@ -1,7 +1,8 @@
name: "bind"
services:
bind:
image: "11notes/bind:9.18.31"
container_name: "bind"
image: "11notes/bind:9.18.35"
command: ["master"]
environment:
TZ: "Europe/Zurich"
volumes:
@@ -11,9 +12,15 @@ services:
- "53:53/udp"
- "53:53/tcp"
- "8053:8053/tcp"
networks:
frontend:
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always
net.ipv4.ip_unprivileged_port_start: 53
restart: "always"
volumes:
etc:
var:
var:
networks:
frontend:

View File

@@ -1,4 +0,0 @@
#!/bin/bash
curl -Lo manifest-tool https://github.com/estesp/manifest-tool/releases/download/v0.9.0/manifest-tool-linux-amd64
chmod +x manifest-tool
./manifest-tool push from-spec multi-arch-manifest-version.yaml

View File

@@ -1,2 +0,0 @@
#!/bin/bash
docker run --rm --privileged multiarch/qemu-user-static:register --reset

View File

@@ -1,11 +0,0 @@
image: 11notes/bind:9.18.31
manifests:
- image: 11notes/bind:9.18.31
platform:
architecture: amd64
os: linux
- image: 11notes/bind:9.18.31
platform:
architecture: arm64
os: linux
variant: v8

36
project.md Normal file
View File

@@ -0,0 +1,36 @@
${{ content_synopsis }} This image will run BIND9 DNS server precompiled for large installations and maximum performance. It also offers three operating modes: Master, Slave and Resolver set via **command: ["mode"]**.
# Master
If run as master, set the IPs of the slaves via *BIND_SLAVES*. Bind will operate with catalog zones for all slaves. You can add new zones via the *addzone* script that requires the zone name and the IP of at least one NS (slave). You can then use nsupdate to update the master with new records and all changes are populates to all slaves automatically. Add a new zone like this:
```shell
docker exec master addzone contoso.com 10.255.53.52
```
It will automatically create a default zone and populate it as well as add a random key for managing the zone via nsupdate or via the dynamically created root key at startup (check /bind/etc/keys.conf for generated keys). Checkout **compose.authoritative.yaml** for an example.
# Slave
If run as slave, make sure you set the *BIND_MASTERS* IPs so they will pickup all changes automatically. The slave enables recursion, so make sure you have a resolver present to resolve queries not handles by the slave. The slave will respond to all IPs on RFC1918 by default. You can setup your own config as well. You can run as many slaves as you like.
# Resolver
If run as a resolver, it will cache all results and use the root zone NS to create its own cache database for all records requested. Make sure the resolver has internet access. The resolver will accept all connections from any RFC1918 address. Checkout **compose.resolver.yaml** for an example.
${{ title_volumes }}
* **${{ json_root }}/etc** - Directory of named.conf
* **${{ json_root }}/var** - Directory of Directory of zone data
${{ content_compose }}
${{ content_defaults }}
${{ content_environment }}
| `BIND_SLAVES` | IPs of bind slaves if using authoritative master (add ;) | |
| `BIND_MASTERS` | IPs of bind master if using authoritative slave (add ;) | |
${{ content_source }}
${{ content_parent }}
${{ content_built }}
${{ content_tips }}

View File

@@ -26,7 +26,7 @@ update add ${UID}.zones.catalog.home.arpa 3600 IN PTR ${1}
send
EOT
elevenLogJSON info "added new zone ${1} to catalog as ${UID}.zones.catalog.home.arpa"
eleven log info "added new zone ${1} to catalog as ${UID}.zones.catalog.home.arpa"
# reload config due to new keys
/opt/bind/sbin/rndc reload &> /dev/null

View File

@@ -2,39 +2,41 @@
NAMED_CONF=${APP_ROOT}/etc/named.conf
RNDC_CONF=${APP_ROOT}/etc/rndc.conf
echo "$@"
if [ -z "${1}" ]; then
echo "custom" > ${APP_ROOT}/etc/mode
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION}"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
eleven log start
else
if echo "$@" | grep -q "resolver"; then
# run bind as a resolver
echo "slave" > ${APP_ROOT}/etc/mode
if [ ! -f "${APP_ROOT}/var/root.db" ]; then
elevenLogJSON info "creating root db for resolver"
eleven log info "creating root db for resolver"
rootdb
fi
if [ ! -f "${NAMED_CONF}" ]; then
elevenLogJSON info "creating resolver configuration"
eleven log info "creating resolver configuration"
cp ${APP_ROOT}/.default/resolver.conf ${NAMED_CONF}
fi
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION} as resolver"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
eleven log info "starting ${APP_NAME} v${APP_VERSION} as resolver"
fi
if echo "$@" | grep -q "master"; then
# run bind as an authoritative master
echo "master" > ${APP_ROOT}/etc/mode
if [ ! -f "${NAMED_CONF}" ]; then
elevenLogJSON info "creating authoritative master configuration"
eleven log info "creating authoritative master configuration"
cp ${APP_ROOT}/.default/authoritative-master.conf ${NAMED_CONF}
cp ${APP_ROOT}/.default/rndc.conf ${RNDC_CONF}
@@ -59,18 +61,18 @@
echo "key \"root\" { algorithm hmac-sha256; secret \"${KEY}\"; };" > ${APP_ROOT}/etc/keys.conf
fi
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION} as authoritative master"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
eleven log info "starting ${APP_NAME} v${APP_VERSION} as authoritative master"
fi
if echo "$@" | grep -q "slave"; then
# run bind as an authoritative slave
echo "slave" > ${APP_ROOT}/etc/mode
if [ ! -f "${NAMED_CONF}" ]; then
elevenLogJSON info "creating authoritative slave configuration"
eleven log info "creating authoritative slave configuration"
cp ${APP_ROOT}/.default/authoritative-slave.conf ${NAMED_CONF}
KEY=$(head -200 /dev/urandom | cksum | cut -f1 -d " " | sha256sum | tr -d "[:space:]-")
@@ -79,11 +81,11 @@
sed -i 's/%KEY%/'${KEY}'/' ${NAMED_CONF}
fi
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION} as authoritative slave"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
eleven log info "starting ${APP_NAME} v${APP_VERSION} as authoritative slave"
fi
fi

View File

@@ -1,2 +0,0 @@
#!/bin/ash
/opt/bind/bin/dig +time=2 +tries=1 . NS @localhost || exit 1

View File

@@ -1,6 +1,6 @@
#!/bin/ash
if [ ! -f "/bind/var/root.db" ]; then
elevenLogJSON debug "no root db found, using IP of a.root"
eleven log debug "no root db found, using IP of a.root"
ROOT_DB_NS=198.41.0.4
else
ROOT_DB_NS=a.root-servers.net