chore: capture Jenkins Docker baseline
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
secrets/*
|
||||||
|
!secrets/.gitkeep
|
||||||
|
|
||||||
|
installers/**/*
|
||||||
|
!installers/**/
|
||||||
|
!installers/**/README.md
|
||||||
|
|
||||||
|
# Locally installed, versioned MCUXpresso SDK bundles
|
||||||
|
sdks/
|
||||||
|
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Local AI/editor settings
|
||||||
|
.claude/
|
||||||
121
README.md
Normal file
121
README.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# Jenkins for firmware builds (MCUXpresso + MPLAB X)
|
||||||
|
|
||||||
|
A general-purpose Jenkins controller plus two toolchain-specific build
|
||||||
|
agents, connected over SSH inside a private Docker network:
|
||||||
|
|
||||||
|
- `jenkins-controller` - lean controller, no toolchains, `numExecutors: 0`
|
||||||
|
so it only orchestrates. Configured entirely via
|
||||||
|
[controller/casc/jenkins.yaml](controller/casc/jenkins.yaml)
|
||||||
|
(JCasC) - security realm, the SSH credential, and both agent node
|
||||||
|
definitions are declared there.
|
||||||
|
- `mcuxpresso-agent` - Ubuntu + NXP's Arm GNU Toolchain/CMake/Ninja, fetched
|
||||||
|
headlessly via `MCUXpressoInstallerCLI` (see
|
||||||
|
[agents/mcuxpresso/Dockerfile](agents/mcuxpresso/Dockerfile) and
|
||||||
|
[installers/mcuxpresso/README.md](installers/mcuxpresso/README.md) for how
|
||||||
|
that actually works - it's not a plain apt package). Jenkins label:
|
||||||
|
`mcuxpresso arm-gcc`.
|
||||||
|
- `mplabx-agent` - Ubuntu + MPLAB X IDE + XC8/XC16/XC32 compilers.
|
||||||
|
Jenkins label: `mplabx`.
|
||||||
|
|
||||||
|
Point pipelines at a toolchain with `agent { label 'mcuxpresso' }` or
|
||||||
|
`agent { label 'mplabx' }`.
|
||||||
|
|
||||||
|
## MCUXpresso SDKs
|
||||||
|
|
||||||
|
SDKs are stored outside the agent container and mounted read-only from the
|
||||||
|
Docker host:
|
||||||
|
|
||||||
|
```text
|
||||||
|
host: /home/brent/jenkins-docker/sdks
|
||||||
|
container: /opt/mcux-sdks
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep each SDK in a versioned directory so pipelines can select one explicitly,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/home/brent/jenkins-docker/sdks/EVK-MIMXRT1020/25.06.00-8a1cd039
|
||||||
|
```
|
||||||
|
|
||||||
|
Set `SdkRootDirPath` in a pipeline when it needs a path other than its project
|
||||||
|
default. The parent directory is mounted read-only, so adding or replacing an
|
||||||
|
SDK is an explicit host-side operation rather than a build side effect.
|
||||||
|
The `sdks/` directory is ignored by Git so initializing and pushing this
|
||||||
|
infrastructure directory does not upload the vendor SDK contents.
|
||||||
|
|
||||||
|
## Why separate images
|
||||||
|
|
||||||
|
Each vendor toolchain is large, versioned independently, and installed from
|
||||||
|
a manually-downloaded, license-gated installer. Keeping them out of the
|
||||||
|
controller means the controller stays small/disposable, and you can
|
||||||
|
rebuild/upgrade one toolchain without touching the other or restarting
|
||||||
|
Jenkins itself.
|
||||||
|
|
||||||
|
## One-time setup
|
||||||
|
|
||||||
|
1. **Get the vendor installers** (both require a free account/login to
|
||||||
|
*download*, so this step can't be automated in the Dockerfile - though
|
||||||
|
the actual component installs that follow don't need any further login):
|
||||||
|
- MCUXpresso Installer (`*.deb.bin`) -> `installers/mcuxpresso/` (see
|
||||||
|
the README there)
|
||||||
|
- MPLAB X + XC8/XC16/XC32 `.sh` installers -> `installers/mplabx/` (see
|
||||||
|
the README there)
|
||||||
|
|
||||||
|
2. **Generate the SSH keypair and admin password**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/setup-secrets.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes `secrets/agent_ssh_key` (+ `.pub`) and
|
||||||
|
`secrets/jenkins_admin_password.txt`. Note the printed password - you'll
|
||||||
|
need it to log in. Nothing in `secrets/` is committed to git.
|
||||||
|
|
||||||
|
3. **Build and start everything**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose build
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Visit http://localhost:8080 and log in as `admin` with the password from
|
||||||
|
step 2. Under **Manage Jenkins > Nodes**, confirm `mcuxpresso-agent` and
|
||||||
|
`mplabx-agent` come online (they connect automatically via the SSH
|
||||||
|
launcher defined in JCasC - no manual node setup needed).
|
||||||
|
|
||||||
|
## Things to verify before relying on this in production
|
||||||
|
|
||||||
|
- **Silent-install flags**: the MPLAB X/XC installer commands in
|
||||||
|
[agents/mplabx/Dockerfile](agents/mplabx/Dockerfile) use
|
||||||
|
`--mode unattended --unattendedmodeui none`, the standard flags for
|
||||||
|
InstallBuilder-based installers, but Microchip hasn't guaranteed this
|
||||||
|
across every release. Run the installer with `--help` locally against the
|
||||||
|
exact version you downloaded before trusting the build.
|
||||||
|
- **Install paths**: the `PATH` set in that same Dockerfile assumes
|
||||||
|
`/opt/microchip/...`; Microchip has changed default install directories
|
||||||
|
across MPLAB X major versions, so confirm it matches what your installer
|
||||||
|
actually chose (check the build logs, or add `-D INSTALL_DIR=...` to pin
|
||||||
|
it explicitly).
|
||||||
|
- **MCUXpresso component versions**: the Dockerfile bakes in whatever
|
||||||
|
`mcux-cli install -c armToolchain cmake ninja` resolves to as "current" at
|
||||||
|
build time (verified working: Arm GNU Toolchain 14.2.1, CMake 3.30.0,
|
||||||
|
Ninja 1.13.2). `mcux-cli install --help` lists older versions too (e.g.
|
||||||
|
Arm GNU Toolchain 13.2.1) but a quick test showed `-c
|
||||||
|
armToolchain:13.2.1`-style pinning is rejected as an invalid choice - I
|
||||||
|
didn't find the right syntax for requesting a non-default version, so
|
||||||
|
for now you get whatever's newest. Worth checking NXP's own docs if you
|
||||||
|
need a pinned version for reproducibility.
|
||||||
|
- **Licensing**: XC8/XC16/XC32 free-tier compilers work out of the box;
|
||||||
|
Standard/Pro tiers need a license file or floating license server, which
|
||||||
|
isn't configured here.
|
||||||
|
- **Host key verification**: the controller's SSH launcher uses
|
||||||
|
`nonVerifyingKeyVerificationStrategy`, fine for an isolated local Docker
|
||||||
|
network but worth tightening (`knownHosts` strategy) if you deploy this
|
||||||
|
beyond your machine.
|
||||||
|
|
||||||
|
## Adding more toolchains later
|
||||||
|
|
||||||
|
Add a new directory under `agents/<name>/Dockerfile`, a matching
|
||||||
|
`installers/<name>/`, a service in `docker-compose.yml`, and a `permanent`
|
||||||
|
node block in `controller/casc/jenkins.yaml` with a distinct label - same
|
||||||
|
pattern as the two agents here.
|
||||||
83
agents/mcuxpresso/Dockerfile
Normal file
83
agents/mcuxpresso/Dockerfile
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
openssh-server openjdk-17-jre-headless git make build-essential python3 \
|
||||||
|
curl unzip ca-certificates xz-utils \
|
||||||
|
# Electron runtime deps: MCUXpressoInstallerCLI ships as an Electron
|
||||||
|
# app and needs these even for headless/CLI use.
|
||||||
|
libglib2.0-0 libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
|
||||||
|
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 \
|
||||||
|
libpango-1.0-0 libcairo2 libasound2 libxshmfence1 libx11-6 libxext6 \
|
||||||
|
libxrender1 libgtk-3-0 xvfb \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN useradd -m -s /bin/bash jenkins \
|
||||||
|
&& mkdir -p /home/jenkins/.ssh /var/run/sshd \
|
||||||
|
&& chmod 700 /home/jenkins/.ssh
|
||||||
|
|
||||||
|
COPY secrets/agent_ssh_key.pub /home/jenkins/.ssh/authorized_keys
|
||||||
|
RUN chown -R jenkins:jenkins /home/jenkins/.ssh \
|
||||||
|
&& chmod 600 /home/jenkins/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# --- MCUXpresso Installer ---------------------------------------------------
|
||||||
|
# NXP no longer ships a plain IDE .deb - the download is "MCUXpresso
|
||||||
|
# Installer", a Makeself-wrapped Electron app (*.deb.bin) that itself
|
||||||
|
# contains a documented headless CLI (MCUXpressoInstallerCLI) for fetching
|
||||||
|
# individual packages/components non-interactively, no NXP account/login
|
||||||
|
# needed at download time. Get it from https://www.nxp.com/mcuxpresso and
|
||||||
|
# place it in installers/mcuxpresso/ before building. See
|
||||||
|
# installers/mcuxpresso/README.md.
|
||||||
|
COPY installers/mcuxpresso/ /tmp/installers/
|
||||||
|
RUN set -e; \
|
||||||
|
INSTALLER=$(ls /tmp/installers/*.deb.bin 2>/dev/null | head -n1); \
|
||||||
|
if [ -z "$INSTALLER" ]; then \
|
||||||
|
echo "ERROR: no MCUXpresso installer (*.deb.bin) found in installers/mcuxpresso/. See installers/mcuxpresso/README.md" >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
chmod +x "$INSTALLER"; \
|
||||||
|
# --noexec: unpack the Makeself payload (install.sh + the real .deb)
|
||||||
|
# without running install.sh, which assumes an interactive desktop user
|
||||||
|
# and does things (desktop icons, chrome-sandbox setuid) we don't need
|
||||||
|
# in a headless CI agent.
|
||||||
|
"$INSTALLER" --target /tmp/mcux_pkg --noprogress --noexec --keep; \
|
||||||
|
DEB=$(ls /tmp/mcux_pkg/*.deb | head -n1); \
|
||||||
|
dpkg -x "$DEB" /opt/mcuxpresso-installer; \
|
||||||
|
rm -rf /tmp/installers /tmp/mcux_pkg; \
|
||||||
|
# The app writes its own logs/cache next to its binary (e.g.
|
||||||
|
# <installdir>/logs/cli.log). Left root-owned, a non-root caller can't
|
||||||
|
# create that path and the app retries the failed write in an infinite
|
||||||
|
# loop instead of erroring out - so it must be writable by the jenkins
|
||||||
|
# user before anything ever invokes it.
|
||||||
|
chown -R jenkins:jenkins /opt/mcuxpresso-installer
|
||||||
|
|
||||||
|
# The installer is Electron; running as root needs a setuid chrome-sandbox
|
||||||
|
# binary we don't bother setting up, and our CI user is unprivileged anyway,
|
||||||
|
# so just disable the sandbox instead.
|
||||||
|
ENV ELECTRON_DISABLE_SANDBOX=1
|
||||||
|
|
||||||
|
# MCUXpressoInstallerCLI still initializes Electron/Chromium under the hood
|
||||||
|
# and needs *a* display even for pure CLI output, so always drive it through
|
||||||
|
# a throwaway Xvfb instance.
|
||||||
|
RUN printf '#!/bin/sh\nexec xvfb-run -a /opt/mcuxpresso-installer/MCUXpressoInstaller/MCUXpressoInstallerCLI "$@"\n' \
|
||||||
|
> /usr/local/bin/mcux-cli \
|
||||||
|
&& chmod +x /usr/local/bin/mcux-cli
|
||||||
|
|
||||||
|
# Bake in a default toolchain so pipelines aren't hitting the network on
|
||||||
|
# every build. `docker run --rm <image> mcux-cli install --help` lists every
|
||||||
|
# available -p/-c package/component and version if you want to change this.
|
||||||
|
USER jenkins
|
||||||
|
RUN mcux-cli install -c armToolchain cmake ninja; \
|
||||||
|
ARMGCC_DIR=$(ls -d /home/jenkins/.mcuxpressotools/arm-gnu-toolchain-*-x86_64-arm-none-eabi | head -n1); \
|
||||||
|
CMAKE_DIR=$(ls -d /home/jenkins/.mcuxpressotools/cmake-*-linux-x86_64 | head -n1); \
|
||||||
|
NINJA_DIR=$(ls -d /home/jenkins/.mcuxpressotools/ninja-* | head -n1); \
|
||||||
|
ln -s "$ARMGCC_DIR" /home/jenkins/.mcuxpressotools/arm-toolchain; \
|
||||||
|
ln -s "$CMAKE_DIR" /home/jenkins/.mcuxpressotools/cmake; \
|
||||||
|
ln -s "$NINJA_DIR" /home/jenkins/.mcuxpressotools/ninja; \
|
||||||
|
test -x /home/jenkins/.mcuxpressotools/arm-toolchain/bin/arm-none-eabi-gcc
|
||||||
|
USER root
|
||||||
|
|
||||||
|
ENV PATH="/home/jenkins/.mcuxpressotools/arm-toolchain/bin:/home/jenkins/.mcuxpressotools/cmake/bin:/home/jenkins/.mcuxpressotools/ninja:${PATH}"
|
||||||
|
|
||||||
|
EXPOSE 22
|
||||||
|
CMD ["/usr/sbin/sshd", "-D"]
|
||||||
72
agents/mplabx/Dockerfile
Normal file
72
agents/mplabx/Dockerfile
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
FROM ubuntu:22.04
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
openssh-server openjdk-17-jre-headless git make build-essential \
|
||||||
|
curl unzip ca-certificates \
|
||||||
|
libxext6 libxrender1 libxtst6 libxi6 libusb-1.0-0 \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
# libX* above: MPLAB X's NetBeans-based platform pulls these in even for
|
||||||
|
# headless/CLI use (mplab_ipe, make-based project builds). Drop them if you
|
||||||
|
# confirm your specific build path never touches the IDE runtime.
|
||||||
|
# libusb-1.0-0: required by the installer's own 64-bit library check (used
|
||||||
|
# for MPLAB IPE's device programming/debug tool support).
|
||||||
|
|
||||||
|
RUN useradd -m -s /bin/bash jenkins \
|
||||||
|
&& mkdir -p /home/jenkins/.ssh /var/run/sshd \
|
||||||
|
&& chmod 700 /home/jenkins/.ssh
|
||||||
|
|
||||||
|
COPY secrets/agent_ssh_key.pub /home/jenkins/.ssh/authorized_keys
|
||||||
|
RUN chown -R jenkins:jenkins /home/jenkins/.ssh \
|
||||||
|
&& chmod 600 /home/jenkins/.ssh/authorized_keys
|
||||||
|
|
||||||
|
# --- MPLAB X IDE + XC8/XC16/XC32 compilers ---------------------------------
|
||||||
|
# Download these from https://www.microchip.com (account required) and place
|
||||||
|
# them in installers/mplabx/ before building this image. See
|
||||||
|
# installers/mplabx/README.md for expected filenames.
|
||||||
|
COPY installers/mplabx/ /tmp/installers/
|
||||||
|
RUN set -e; \
|
||||||
|
IDE_INSTALLER=$(ls /tmp/installers/MPLABX*.sh 2>/dev/null | head -n1); \
|
||||||
|
if [ -z "$IDE_INSTALLER" ]; then \
|
||||||
|
echo "ERROR: no MPLAB X installer (MPLABX-*-linux-installer.sh) found in installers/mplabx/. See installers/mplabx/README.md" >&2; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
chmod +x "$IDE_INSTALLER"; \
|
||||||
|
# These installers are makeself wrappers around an InstallBuilder elf
|
||||||
|
# installer: flags before "--" go to the makeself wrapper itself
|
||||||
|
# (--target, --nox11, ...); flags after "--" are passed through to the
|
||||||
|
# embedded installer (--mode, --unattendedmodeui, --installdir, ...).
|
||||||
|
# The wrapper's root check greps $USER (unset under plain `sh -c`, as
|
||||||
|
# Docker RUN uses) rather than trusting uid 0, so export it explicitly.
|
||||||
|
export USER=root; \
|
||||||
|
"$IDE_INSTALLER" --nox11 -- --mode unattended --unattendedmodeui none --installdir /opt/microchip/mplabx; \
|
||||||
|
# XC compiler installers ship in two different forms depending on
|
||||||
|
# version: a makeself-wrapped "*.sh" (same two-tier flag convention as
|
||||||
|
# the IDE installer above, taking --installdir) or a bare InstallBuilder
|
||||||
|
# elf "*.run" (flags passed directly, taking --prefix instead). Detect
|
||||||
|
# which by sniffing the first two bytes ("#!" vs the ELF magic).
|
||||||
|
for XC in /tmp/installers/xc8*.sh /tmp/installers/xc8*.run \
|
||||||
|
/tmp/installers/xc16*.sh /tmp/installers/xc16*.run \
|
||||||
|
/tmp/installers/xc32*.sh /tmp/installers/xc32*.run; do \
|
||||||
|
[ -f "$XC" ] || continue; \
|
||||||
|
chmod +x "$XC"; \
|
||||||
|
XC_NAME=$(basename "$XC" | cut -d- -f1); \
|
||||||
|
if [ "$(head -c2 "$XC")" = "#!" ]; then \
|
||||||
|
"$XC" --nox11 -- --mode unattended --unattendedmodeui none --installdir "/opt/microchip/$XC_NAME"; \
|
||||||
|
else \
|
||||||
|
"$XC" --mode unattended --unattendedmodeui none --prefix "/opt/microchip/$XC_NAME"; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
rm -rf /tmp/installers
|
||||||
|
|
||||||
|
ENV PATH="/opt/microchip/mplabx/mplab_platform/bin:/opt/microchip/xc8/bin:/opt/microchip/xc16/bin:/opt/microchip/xc32/bin:${PATH}"
|
||||||
|
# The IDE installer also symlinks its main executables (mplab_ide, mplab_ipe,
|
||||||
|
# mdb, prjMakefilesGenerator, projectPackager) into /usr/bin directly, so
|
||||||
|
# they work even without the mplab_platform/bin entry above.
|
||||||
|
# --installdir/--prefix above pin each install to an unversioned path, but
|
||||||
|
# the bin/ subdirectory layout inside it can still vary by installer version
|
||||||
|
# - if `docker compose run mplabx-agent which xc32-gcc` (or mdb, etc.) comes
|
||||||
|
# up empty, inspect /opt/microchip/*/ in the built image and adjust PATH.
|
||||||
|
|
||||||
|
EXPOSE 22
|
||||||
|
CMD ["/usr/sbin/sshd", "-D"]
|
||||||
7
controller/Dockerfile
Normal file
7
controller/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FROM jenkins/jenkins:lts-jdk17
|
||||||
|
|
||||||
|
COPY controller/plugins.txt /usr/share/jenkins/ref/plugins.txt
|
||||||
|
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt
|
||||||
|
|
||||||
|
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"
|
||||||
|
ENV CASC_JENKINS_CONFIG="/var/jenkins_home/casc_configs/jenkins.yaml"
|
||||||
73
controller/casc/jenkins.yaml
Normal file
73
controller/casc/jenkins.yaml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
jenkins:
|
||||||
|
systemMessage: "Firmware build Jenkins controller - configured via JCasC"
|
||||||
|
# Controller stays a pure orchestrator; real builds run on the labeled
|
||||||
|
# toolchain agents below. Bump this if you want the controller itself
|
||||||
|
# to run lightweight jobs (e.g. git checkout/fan-out stages).
|
||||||
|
numExecutors: 0
|
||||||
|
securityRealm:
|
||||||
|
local:
|
||||||
|
allowsSignup: false
|
||||||
|
users:
|
||||||
|
- id: "${JENKINS_ADMIN_ID}"
|
||||||
|
password: "${JENKINS_ADMIN_PASSWORD}"
|
||||||
|
authorizationStrategy:
|
||||||
|
loggedInUsersCanDoAnything:
|
||||||
|
allowAnonymousRead: false
|
||||||
|
nodes:
|
||||||
|
- permanent:
|
||||||
|
name: "mcuxpresso-agent"
|
||||||
|
remoteFS: "/home/jenkins"
|
||||||
|
labelString: "mcuxpresso arm-gcc"
|
||||||
|
numExecutors: 2
|
||||||
|
mode: EXCLUSIVE
|
||||||
|
launcher:
|
||||||
|
ssh:
|
||||||
|
host: "mcuxpresso-agent"
|
||||||
|
port: 22
|
||||||
|
credentialsId: "agent-ssh-key"
|
||||||
|
launchTimeoutSeconds: 60
|
||||||
|
maxNumRetries: 5
|
||||||
|
retryWaitTime: 15
|
||||||
|
sshHostKeyVerificationStrategy:
|
||||||
|
nonVerifyingKeyVerificationStrategy: {}
|
||||||
|
- permanent:
|
||||||
|
name: "mplabx-agent"
|
||||||
|
remoteFS: "/home/jenkins"
|
||||||
|
labelString: "mplabx"
|
||||||
|
numExecutors: 2
|
||||||
|
mode: EXCLUSIVE
|
||||||
|
launcher:
|
||||||
|
ssh:
|
||||||
|
host: "mplabx-agent"
|
||||||
|
port: 22
|
||||||
|
credentialsId: "agent-ssh-key"
|
||||||
|
launchTimeoutSeconds: 60
|
||||||
|
maxNumRetries: 5
|
||||||
|
retryWaitTime: 15
|
||||||
|
sshHostKeyVerificationStrategy:
|
||||||
|
nonVerifyingKeyVerificationStrategy: {}
|
||||||
|
|
||||||
|
credentials:
|
||||||
|
system:
|
||||||
|
domainCredentials:
|
||||||
|
- credentials:
|
||||||
|
- basicSSHUserPrivateKey:
|
||||||
|
scope: GLOBAL
|
||||||
|
id: "agent-ssh-key"
|
||||||
|
username: "jenkins"
|
||||||
|
privateKeySource:
|
||||||
|
directEntry:
|
||||||
|
privateKey: "${AGENT_SSH_PRIVATE_KEY}"
|
||||||
|
|
||||||
|
- basicSSHUserPrivateKey:
|
||||||
|
scope: GLOBAL
|
||||||
|
id: "gitea-ultra2-app"
|
||||||
|
description: "Read-only deploy key for mate/ultra2-app"
|
||||||
|
username: "git"
|
||||||
|
privateKeySource:
|
||||||
|
directEntry:
|
||||||
|
privateKey: "${GITEA_ULTRA2_APP_PRIVATE_KEY}"
|
||||||
|
|
||||||
|
unclassified:
|
||||||
|
location:
|
||||||
|
url: "https://jenkins.sparksoftdesign.com/"
|
||||||
5
controller/plugins.txt
Normal file
5
controller/plugins.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
configuration-as-code
|
||||||
|
ssh-slaves
|
||||||
|
git
|
||||||
|
workflow-aggregator
|
||||||
|
credentials-binding
|
||||||
56
docker-compose.yml
Normal file
56
docker-compose.yml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
services:
|
||||||
|
jenkins-controller:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: controller/Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8090:8080"
|
||||||
|
environment:
|
||||||
|
JENKINS_ADMIN_ID: "admin"
|
||||||
|
secrets:
|
||||||
|
- source: agent_ssh_private_key
|
||||||
|
target: AGENT_SSH_PRIVATE_KEY
|
||||||
|
- source: gitea_ultra2_app_private_key
|
||||||
|
target: GITEA_ULTRA2_APP_PRIVATE_KEY
|
||||||
|
- source: jenkins_admin_password
|
||||||
|
target: JENKINS_ADMIN_PASSWORD
|
||||||
|
volumes:
|
||||||
|
- jenkins_home:/var/jenkins_home
|
||||||
|
- ./controller/casc:/var/jenkins_home/casc_configs:ro
|
||||||
|
networks:
|
||||||
|
- jenkins-net
|
||||||
|
|
||||||
|
mcuxpresso-agent:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: agents/mcuxpresso/Dockerfile
|
||||||
|
hostname: mcuxpresso-agent
|
||||||
|
ports:
|
||||||
|
- "2222:22"
|
||||||
|
volumes:
|
||||||
|
- ./sdks:/opt/mcux-sdks:ro
|
||||||
|
- ./secrets/gitea_known_hosts:/etc/ssh/ssh_known_hosts:ro
|
||||||
|
networks:
|
||||||
|
- jenkins-net
|
||||||
|
|
||||||
|
mplabx-agent:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: agents/mplabx/Dockerfile
|
||||||
|
hostname: mplabx-agent
|
||||||
|
networks:
|
||||||
|
- jenkins-net
|
||||||
|
|
||||||
|
networks:
|
||||||
|
jenkins-net:
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
jenkins_home:
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
agent_ssh_private_key:
|
||||||
|
file: ./secrets/agent_ssh_key
|
||||||
|
gitea_ultra2_app_private_key:
|
||||||
|
file: ./secrets/gitea_ultra2_app_key
|
||||||
|
jenkins_admin_password:
|
||||||
|
file: ./secrets/jenkins_admin_password.txt
|
||||||
27
installers/mcuxpresso/README.md
Normal file
27
installers/mcuxpresso/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# MCUXpresso installer
|
||||||
|
|
||||||
|
Download "MCUXpresso Installer" (not a plain IDE package - NXP replaced that
|
||||||
|
with an installer app) from https://www.nxp.com/mcuxpresso (NXP account
|
||||||
|
required) and place the Linux download in this directory before running
|
||||||
|
`docker compose build mcuxpresso-agent`.
|
||||||
|
|
||||||
|
The file NXP ships is named something like `MCUXpressoInstaller.deb.bin` - a
|
||||||
|
Makeself self-extracting archive wrapping an Electron app, not a `.deb` you
|
||||||
|
can `apt install` directly. The Dockerfile unpacks it, pulls out the real
|
||||||
|
`.deb` inside, and uses the app's bundled `MCUXpressoInstallerCLI` binary to
|
||||||
|
fetch the toolchain non-interactively (no NXP login needed for the actual
|
||||||
|
component downloads - see the Dockerfile for how). It picks up the first
|
||||||
|
`*.deb.bin` it finds here, so you only need one file present at a time.
|
||||||
|
|
||||||
|
By default the image bakes in the Arm GNU Toolchain, CMake, and Ninja (see
|
||||||
|
`agents/mcuxpresso/Dockerfile`). To install additional packages/components
|
||||||
|
(e.g. an MCUXpresso SDK bundle, LinkServer, SEGGER J-Link support), run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm jenkins-docker-mcuxpresso-agent mcux-cli install --help
|
||||||
|
```
|
||||||
|
|
||||||
|
to see every available `-p`/`-c` choice, then add them to the `mcux-cli
|
||||||
|
install` line in the Dockerfile.
|
||||||
|
|
||||||
|
This directory is gitignored except for this README.
|
||||||
16
installers/mplabx/README.md
Normal file
16
installers/mplabx/README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# MPLAB X installer
|
||||||
|
|
||||||
|
Download the following Linux installers from
|
||||||
|
https://www.microchip.com/mplab/mplab-x-ide (Microchip account required) and
|
||||||
|
place them in this directory before running
|
||||||
|
`docker compose build mplabx-agent`:
|
||||||
|
|
||||||
|
- `MPLABX-<version>-linux-installer.sh` (required)
|
||||||
|
- `xc8-<version>-full-install-linux-x64-installer.{sh,run}` (optional, if you need the XC8 compiler)
|
||||||
|
- `xc16-<version>-full-install-linux-installer.{sh,run}` (optional, if you need the XC16 compiler)
|
||||||
|
- `xc32-<version>-full-install-linux-installer.{sh,run}` (optional, if you need the XC32 compiler)
|
||||||
|
|
||||||
|
The Dockerfile globs for these filename prefixes, so exact version numbers
|
||||||
|
don't matter. XC compiler installers ship as either a `.sh` (makeself-
|
||||||
|
wrapped) or a bare `.run` (ELF) installer depending on version - both are
|
||||||
|
handled. This directory is gitignored except for this README.
|
||||||
42
nginx/jenkins.sparksoftdesign.com.conf
Normal file
42
nginx/jenkins.sparksoftdesign.com.conf
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
server {
|
||||||
|
server_name jenkins.sparksoftdesign.com;
|
||||||
|
|
||||||
|
client_max_body_size 500M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:8090;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_request_buffering off;
|
||||||
|
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
proxy_set_header X-Forwarded-Port $server_port;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Jenkins inbound WebSocket agents use this same endpoint.
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_read_timeout 86400s;
|
||||||
|
proxy_send_timeout 86400s;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen [::]:443 ssl ipv6only=on; # managed by Certbot
|
||||||
|
listen 443 ssl; # managed by Certbot
|
||||||
|
ssl_certificate /etc/letsencrypt/live/jenkins.sparksoftdesign.com/fullchain.pem; # managed by Certbot
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/jenkins.sparksoftdesign.com/privkey.pem; # managed by Certbot
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
if ($host = jenkins.sparksoftdesign.com) {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
} # managed by Certbot
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name jenkins.sparksoftdesign.com;
|
||||||
|
return 404; # managed by Certbot
|
||||||
|
}
|
||||||
23
scripts/setup-secrets.sh
Executable file
23
scripts/setup-secrets.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Generates the SSH keypair (controller -> agents) and the Jenkins admin
|
||||||
|
# password consumed by docker-compose.yml as Docker secrets. Safe to re-run;
|
||||||
|
# it skips anything that already exists.
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
mkdir -p secrets
|
||||||
|
|
||||||
|
if [ ! -f secrets/agent_ssh_key ]; then
|
||||||
|
ssh-keygen -t ed25519 -f secrets/agent_ssh_key -N "" -C "jenkins-agent"
|
||||||
|
echo "Generated secrets/agent_ssh_key(.pub)"
|
||||||
|
else
|
||||||
|
echo "secrets/agent_ssh_key already exists, skipping"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f secrets/jenkins_admin_password.txt ]; then
|
||||||
|
openssl rand -base64 18 > secrets/jenkins_admin_password.txt
|
||||||
|
echo "Generated Jenkins admin password (saved to secrets/jenkins_admin_password.txt):"
|
||||||
|
cat secrets/jenkins_admin_password.txt
|
||||||
|
else
|
||||||
|
echo "secrets/jenkins_admin_password.txt already exists, skipping"
|
||||||
|
fi
|
||||||
0
secrets/.gitkeep
Normal file
0
secrets/.gitkeep
Normal file
Reference in New Issue
Block a user