├── .github └── workflows │ ├── ci.yml │ └── stale-workflow-queue-cleanup.yml ├── Dockerfile.base ├── Dockerfile.ci ├── Dockerfile.devel ├── LICENSE ├── README.md ├── bash_completion └── entrypoint.sh /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - v*-branch 8 | tags: 9 | - v* 10 | pull_request: 11 | branches: 12 | - main 13 | - v*-branch 14 | 15 | permissions: 16 | packages: write 17 | 18 | concurrency: 19 | group: ${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | env: 23 | DOCKERHUB_BASE: docker.io/zephyrprojectrtos 24 | GHCR_BASE: ghcr.io/zephyrproject-rtos 25 | BASE_IMAGE_NAME: ci-base 26 | CI_IMAGE_NAME: ci 27 | DEVELOPER_IMAGE_NAME: zephyr-build 28 | 29 | jobs: 30 | build: 31 | name: Build (${{ matrix.variant.platform }}) 32 | runs-on: 33 | group: ${{ matrix.variant.builder }} 34 | container: 35 | image: ghcr.io/zephyrproject-rtos/image-build:v1.1.0 36 | 37 | strategy: 38 | fail-fast: true 39 | matrix: 40 | variant: 41 | - platform: linux/amd64 42 | arch: amd64 43 | builder: zephyr-runner-v2-linux-x64-4xlarge 44 | - platform: linux/arm64 45 | arch: arm64 46 | builder: zephyr-runner-v2-linux-arm64-4xlarge 47 | 48 | steps: 49 | - name: Print cloud service information 50 | run: | 51 | echo "ZEPHYR_RUNNER_CLOUD_PROVIDER = ${ZEPHYR_RUNNER_CLOUD_PROVIDER}" 52 | echo "ZEPHYR_RUNNER_CLOUD_NODE = ${ZEPHYR_RUNNER_CLOUD_NODE}" 53 | echo "ZEPHYR_RUNNER_CLOUD_POD = ${ZEPHYR_RUNNER_CLOUD_POD}" 54 | 55 | - name: Configure temporary directory 56 | run: | 57 | mkdir -p /__w/tmp 58 | echo "TMPDIR=/__w/tmp" >> $GITHUB_ENV 59 | 60 | - name: Configure container storage 61 | run: | 62 | sed -i 's/graphroot = .*/graphroot = "\/__w\/container_storage"/' /etc/containers/storage.conf 63 | mkdir -p /__w/container_storage 64 | 65 | - name: Checkout 66 | uses: actions/checkout@v4 67 | 68 | - name: Login to DockerHub 69 | if: ${{ github.event_name != 'pull_request' }} 70 | uses: redhat-actions/podman-login@v1 71 | with: 72 | registry: docker.io 73 | username: ${{ vars.DOCKERHUB_USERNAME }} 74 | password: ${{ secrets.DOCKERHUB_TOKEN }} 75 | 76 | - name: Login to GitHub Container Registry 77 | if: ${{ github.event_name != 'pull_request' }} 78 | uses: redhat-actions/podman-login@v1 79 | with: 80 | registry: ghcr.io 81 | username: ${{ github.repository_owner }} 82 | password: ${{ secrets.GITHUB_TOKEN }} 83 | 84 | - name: Generate metadata for base image 85 | id: meta_base 86 | uses: docker/metadata-action@v5 87 | with: 88 | images: | 89 | ${{ env.DOCKERHUB_BASE }}/${{ env.BASE_IMAGE_NAME }} 90 | ${{ env.GHCR_BASE }}/${{ env.BASE_IMAGE_NAME }} 91 | flavor: | 92 | latest=false 93 | suffix=-${{ matrix.variant.arch }} 94 | tags: | 95 | type=ref,event=branch 96 | type=ref,event=tag 97 | type=ref,event=pr 98 | 99 | - name: Generate metadata for CI image 100 | id: meta_ci 101 | uses: docker/metadata-action@v5 102 | with: 103 | images: | 104 | ${{ env.DOCKERHUB_BASE }}/${{ env.CI_IMAGE_NAME }} 105 | ${{ env.GHCR_BASE }}/${{ env.CI_IMAGE_NAME }} 106 | flavor: | 107 | latest=false 108 | suffix=-${{ matrix.variant.arch }} 109 | tags: | 110 | type=ref,event=branch 111 | type=ref,event=tag 112 | type=ref,event=pr 113 | 114 | - name: Generate metadata for Developer image 115 | id: meta_developer 116 | uses: docker/metadata-action@v5 117 | with: 118 | images: | 119 | ${{ env.DOCKERHUB_BASE }}/${{ env.DEVELOPER_IMAGE_NAME }} 120 | ${{ env.GHCR_BASE }}/${{ env.DEVELOPER_IMAGE_NAME }} 121 | flavor: | 122 | latest=false 123 | suffix=-${{ matrix.variant.arch }} 124 | tags: | 125 | type=ref,event=branch 126 | type=ref,event=tag 127 | type=ref,event=pr 128 | 129 | - name: Generate base image build arguments 130 | id: buildarg_base 131 | run: | 132 | { 133 | echo "args<> $GITHUB_OUTPUT 141 | 142 | - name: Generate CI image build arguments 143 | id: buildarg_ci 144 | run: | 145 | { 146 | echo "args<> $GITHUB_OUTPUT 155 | 156 | - name: Generate Developer image build arguments 157 | id: buildarg_developer 158 | run: | 159 | { 160 | echo "args<> $GITHUB_OUTPUT 169 | 170 | - name: Build base image 171 | uses: redhat-actions/buildah-build@v2 172 | with: 173 | context: . 174 | containerfiles: Dockerfile.base 175 | tags: ${{ steps.meta_base.outputs.tags }} 176 | labels: ${{ steps.meta_base.outputs.labels }} 177 | build-args: ${{ steps.buildarg_base.outputs.args }} 178 | 179 | - name: Build CI image 180 | uses: redhat-actions/buildah-build@v2 181 | with: 182 | context: . 183 | containerfiles: Dockerfile.ci 184 | tags: ${{ steps.meta_ci.outputs.tags }} 185 | labels: ${{ steps.meta_ci.outputs.labels }} 186 | build-args: ${{ steps.buildarg_ci.outputs.args }} 187 | extra-args: | 188 | --pull-never 189 | 190 | - name: Build Developer image 191 | uses: redhat-actions/buildah-build@v2 192 | with: 193 | context: . 194 | containerfiles: Dockerfile.devel 195 | tags: ${{ steps.meta_developer.outputs.tags }} 196 | labels: ${{ steps.meta_developer.outputs.labels }} 197 | build-args: ${{ steps.buildarg_developer.outputs.args }} 198 | extra-args: | 199 | --pull-never 200 | 201 | - name: Push base image 202 | if: ${{ github.event_name != 'pull_request' }} 203 | uses: redhat-actions/push-to-registry@v2 204 | with: 205 | tags: ${{ steps.meta_base.outputs.tags }} 206 | 207 | - name: Push CI image 208 | if: ${{ github.event_name != 'pull_request' }} 209 | uses: redhat-actions/push-to-registry@v2 210 | with: 211 | tags: ${{ steps.meta_ci.outputs.tags }} 212 | 213 | - name: Push Developer image 214 | if: ${{ github.event_name != 'pull_request' }} 215 | uses: redhat-actions/push-to-registry@v2 216 | with: 217 | tags: ${{ steps.meta_developer.outputs.tags }} 218 | 219 | merge: 220 | name: Merge 221 | runs-on: 222 | group: zephyr-runner-v2-linux-x64-4xlarge 223 | container: 224 | image: ghcr.io/zephyrproject-rtos/image-build:v1.0.0 225 | needs: build 226 | if: ${{ github.event_name != 'pull_request' }} 227 | 228 | steps: 229 | - name: Print cloud service information 230 | run: | 231 | echo "ZEPHYR_RUNNER_CLOUD_PROVIDER = ${ZEPHYR_RUNNER_CLOUD_PROVIDER}" 232 | echo "ZEPHYR_RUNNER_CLOUD_NODE = ${ZEPHYR_RUNNER_CLOUD_NODE}" 233 | echo "ZEPHYR_RUNNER_CLOUD_POD = ${ZEPHYR_RUNNER_CLOUD_POD}" 234 | 235 | - name: Configure temporary directory 236 | run: | 237 | mkdir -p /__w/tmp 238 | echo "TMPDIR=/__w/tmp" >> $GITHUB_ENV 239 | 240 | - name: Configure container storage 241 | run: | 242 | sed -i 's/graphroot = .*/graphroot = "\/__w\/container_storage"/' /etc/containers/storage.conf 243 | mkdir -p /__w/container_storage 244 | 245 | - name: Login to DockerHub 246 | if: ${{ github.event_name != 'pull_request' }} 247 | uses: redhat-actions/podman-login@v1 248 | with: 249 | registry: docker.io 250 | username: ${{ vars.DOCKERHUB_USERNAME }} 251 | password: ${{ secrets.DOCKERHUB_TOKEN }} 252 | 253 | - name: Login to GitHub Container Registry 254 | if: ${{ github.event_name != 'pull_request' }} 255 | uses: redhat-actions/podman-login@v1 256 | with: 257 | registry: ghcr.io 258 | username: ${{ github.repository_owner }} 259 | password: ${{ secrets.GITHUB_TOKEN }} 260 | 261 | - name: Generate metadata for base image 262 | id: meta_base 263 | uses: docker/metadata-action@v5 264 | with: 265 | images: | 266 | ${{ env.DOCKERHUB_BASE }}/${{ env.BASE_IMAGE_NAME }} 267 | ${{ env.GHCR_BASE }}/${{ env.BASE_IMAGE_NAME }} 268 | flavor: | 269 | latest=false 270 | tags: | 271 | type=ref,event=branch 272 | type=ref,event=tag 273 | type=raw,value=latest,enable={{is_default_branch}} 274 | 275 | - name: Generate metadata for CI image 276 | id: meta_ci 277 | uses: docker/metadata-action@v5 278 | with: 279 | images: | 280 | ${{ env.DOCKERHUB_BASE }}/${{ env.CI_IMAGE_NAME }} 281 | ${{ env.GHCR_BASE }}/${{ env.CI_IMAGE_NAME }} 282 | flavor: | 283 | latest=false 284 | tags: | 285 | type=ref,event=branch 286 | type=ref,event=tag 287 | type=raw,value=latest,enable={{is_default_branch}} 288 | 289 | - name: Generate metadata for Developer image 290 | id: meta_developer 291 | uses: docker/metadata-action@v5 292 | with: 293 | images: | 294 | ${{ env.DOCKERHUB_BASE }}/${{ env.DEVELOPER_IMAGE_NAME }} 295 | ${{ env.GHCR_BASE }}/${{ env.DEVELOPER_IMAGE_NAME }} 296 | flavor: | 297 | latest=false 298 | tags: | 299 | type=ref,event=branch 300 | type=ref,event=tag 301 | type=raw,value=latest,enable={{is_default_branch}} 302 | 303 | - name: Create multi-architecture image 304 | run: | 305 | archs=(amd64 arm64) 306 | 307 | base_image="${{ env.GHCR_BASE }}/${{ env.BASE_IMAGE_NAME }}:${{ steps.meta_base.outputs.version }}" 308 | ci_image="${{ env.GHCR_BASE }}/${{ env.CI_IMAGE_NAME }}:${{ steps.meta_ci.outputs.version }}" 309 | developer_image="${{ env.GHCR_BASE }}/${{ env.DEVELOPER_IMAGE_NAME }}:${{ steps.meta_developer.outputs.version }}" 310 | 311 | base_image_tags="${{ steps.meta_base.outputs.tags }}" 312 | ci_image_tags="${{ steps.meta_ci.outputs.tags }}" 313 | developer_image_tags="${{ steps.meta_developer.outputs.tags }}" 314 | 315 | # Pull architecture-specific images. 316 | for arch in ${archs[@]}; do 317 | podman pull ${base_image}-${arch} 318 | podman pull ${ci_image}-${arch} 319 | podman pull ${developer_image}-${arch} 320 | done 321 | 322 | # Create multi-architecture images. 323 | for arch in ${archs[@]}; do 324 | base_image_amend_flags+="--amend ${base_image}-${arch} " 325 | ci_image_amend_flags+="--amend ${ci_image}-${arch} " 326 | developer_image_amend_flags+="--amend ${developer_image}-${arch} " 327 | done 328 | 329 | podman manifest create ${base_image} ${base_image_amend_flags} 330 | podman manifest create ${ci_image} ${ci_image_amend_flags} 331 | podman manifest create ${developer_image} ${developer_image_amend_flags} 332 | 333 | # Create base image tags. 334 | for tag in ${base_image_tags}; do 335 | podman tag ${base_image} ${tag} 336 | done 337 | 338 | # Create CI image tags. 339 | for tag in ${ci_image_tags}; do 340 | podman tag ${ci_image} ${tag} 341 | done 342 | 343 | # Create developer image tags. 344 | for tag in ${developer_image_tags}; do 345 | podman tag ${developer_image} ${tag} 346 | done 347 | 348 | - name: Push base image 349 | uses: redhat-actions/push-to-registry@v2 350 | with: 351 | tags: ${{ steps.meta_base.outputs.tags }} 352 | 353 | - name: Push CI image 354 | uses: redhat-actions/push-to-registry@v2 355 | with: 356 | tags: ${{ steps.meta_ci.outputs.tags }} 357 | 358 | - name: Push Developer image 359 | uses: redhat-actions/push-to-registry@v2 360 | with: 361 | tags: ${{ steps.meta_developer.outputs.tags }} 362 | -------------------------------------------------------------------------------- /.github/workflows/stale-workflow-queue-cleanup.yml: -------------------------------------------------------------------------------- 1 | name: Stale Workflow Queue Cleanup 2 | 3 | on: 4 | workflow_dispatch: 5 | branches: [ main ] 6 | schedule: 7 | # everyday at 15:00 8 | - cron: '0 15 * * *' 9 | 10 | concurrency: 11 | group: stale-workflow-queue-cleanup 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | cleanup: 16 | name: Cleanup 17 | runs-on: ubuntu-20.04 18 | 19 | steps: 20 | - name: Delete stale queued workflow runs 21 | uses: MajorScruffy/delete-old-workflow-runs@v0.3.0 22 | with: 23 | repository: ${{ github.repository }} 24 | # Remove any workflow runs in "queued" state for more than 1 day 25 | older-than-seconds: 86400 26 | status: queued 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | -------------------------------------------------------------------------------- /Dockerfile.base: -------------------------------------------------------------------------------- 1 | # Base Image (ci-base) 2 | 3 | FROM ubuntu:24.04 4 | 5 | ARG USERNAME=user 6 | ARG UID=1000 7 | ARG GID=1000 8 | ARG PYTHON_VENV_PATH=/opt/python/venv 9 | ARG UBUNTU_MIRROR_ARCHIVE=archive.ubuntu.com/ubuntu 10 | ARG UBUNTU_MIRROR_SECURITY=security.ubuntu.com/ubuntu 11 | ARG UBUNTU_MIRROR_PORTS=ports.ubuntu.com/ubuntu-ports 12 | 13 | # Set default shell during Docker image build to bash 14 | SHELL ["/bin/bash", "-eo", "pipefail", "-c"] 15 | 16 | # Set non-interactive frontend for apt-get to skip any user confirmations 17 | ENV DEBIAN_FRONTEND=noninteractive 18 | 19 | # Install APT packages 20 | RUN < /etc/sudoers.d/$USERNAME 200 | chmod 0440 /etc/sudoers.d/$USERNAME 201 | EOF 202 | 203 | # Ensure that container runs in the 'root' user context 204 | USER root 205 | -------------------------------------------------------------------------------- /Dockerfile.ci: -------------------------------------------------------------------------------- 1 | # CI Image (ci) 2 | 3 | ARG BASE_IMAGE 4 | FROM ${BASE_IMAGE:-zephyrprojectrtos/ci-base:latest} 5 | 6 | ARG USERNAME=user 7 | ARG WGET_ARGS="-q --show-progress --progress=bar:force:noscroll" 8 | ARG UBUNTU_MIRROR_ARCHIVE=archive.ubuntu.com/ubuntu 9 | ARG UBUNTU_MIRROR_SECURITY=security.ubuntu.com/ubuntu 10 | ARG UBUNTU_MIRROR_PORTS=ports.ubuntu.com/ubuntu-ports 11 | 12 | ARG ZSDK_VERSION=0.17.2 13 | ENV ZSDK_VERSION=$ZSDK_VERSION 14 | ARG KITWARE_NINJA_VERSION=1.11.1.g95dee.kitware.jobserver-1 15 | ENV KITWARE_NINJA_VERSION=$KITWARE_NINJA_VERSION 16 | ARG CCACHE_VERSION=4.9.1 17 | ENV CCACHE_VERSION=$CCACHE_VERSION 18 | ARG DOXYGEN_VERSION=1.14.0 19 | ENV DOXYGEN_VERSION=$DOXYGEN_VERSION 20 | ARG RENODE_VERSION=1.15.3 21 | ENV RENODE_VERSION=$RENODE_VERSION 22 | ARG LLVM_VERSION=20 23 | ENV LLVM_VERSION=$LLVM_VERSION 24 | ARG BSIM_VERSION=v2.7 25 | ENV BSIM_VERSION=$BSIM_VERSION 26 | ARG SPARSE_VERSION=9212270048c3bd23f56c20a83d4f89b870b2b26e 27 | ENV SPARSE_VERSION=$SPARSE_VERSION 28 | ARG PROTOC_VERSION=21.7 29 | ENV PROTOC_VERSION=$PROTOC_VERSION 30 | ARG FVP_BASE_REVC_VERSION=11.27_19 31 | ENV FVP_BASE_REVC_VERSION=$FVP_BASE_REVC_VERSION 32 | ARG FVP_BASE_AEMV8R_VERSION=11.27_19 33 | ENV FVP_BASE_AEMV8R_VERSION=$FVP_BASE_AEMV8R_VERSION 34 | ARG FVP_CORSTONE300_VERSION=11.27_42 35 | ENV FVP_CORSTONE300_VERSION=$FVP_CORSTONE300_VERSION 36 | ARG FVP_CORSTONE310_VERSION=11.27_42 37 | ENV FVP_CORSTONE310_VERSION=$FVP_CORSTONE310_VERSION 38 | ARG FVP_CORSTONE315_VERSION=11.27_42 39 | ENV FVP_CORSTONE315_VERSION=$FVP_CORSTONE315_VERSION 40 | ARG FVP_CORSTONE320_VERSION=11.27_25 41 | ENV FVP_CORSTONE320_VERSION=$FVP_CORSTONE320_VERSION 42 | 43 | # Install APT packages 44 | RUN < ./version 120 | chmod ag+w . -R 121 | ln -s /opt/bsim_west/bsim /opt/bsim 122 | EOF 123 | 124 | # Install sparse package for static analysis 125 | RUN < . 70 | docker build -f Dockerfile.ci --build-arg BASE_IMAGE=zephyr-ci-base:v -t zephyr-ci:v . 71 | docker build -f Dockerfile.devel --build-arg BASE_IMAGE=zephyr-ci:v -t zephyr-build:v . 72 | ``` 73 | 74 | It can be used for building Zephyr samples and tests by mounting the Zephyr workspace into it: 75 | 76 | ``` 77 | docker run -ti -v :/workdir zephyr-build:v 78 | ``` 79 | 80 | #### Using SSH Agent with Docker Image 81 | 82 | The docker images can be built to use the SSH agent on the host to provide authorization 83 | to assets like restricted git repos. To do this there are a few requirements. One of which 84 | is that the user name of the processes inside the docker container must match the real user 85 | name on the host. The USERNAME build argument can be passed into the build process to override 86 | the default user name. Note that all three images need to be built locally with this USERNAME 87 | argument set correctly. 88 | 89 | ``` 90 | docker build -f Dockerfile.base \ 91 | --build-arg UID=$(id -u) \ 92 | --build-arg GID=$(id -g) \ 93 | --build-arg USERNAME=$(id -u -n) \ 94 | -t ci-base: . 95 | ``` 96 | ``` 97 | docker build -f Dockerfile.ci \ 98 | --build-arg UID=$(id -u) \ 99 | --build-arg GID=$(id -g) \ 100 | --build-arg USERNAME=$(id -u -n) \ 101 | --build-arg BASE_IMAGE=ci-base:v4.0-branch \ 102 | -t ci: . 103 | ``` 104 | ``` 105 | docker build -f Dockerfile.devel \ 106 | --build-arg UID=$(id -u) \ 107 | --build-arg GID=$(id -g) \ 108 | --build-arg USERNAME=$(id -u -n) \ 109 | --build-arg BASE_IMAGE=ci:v4.0-branch \ 110 | -t devel: . 111 | ``` 112 | 113 | Then when running the ci or devel image there are additional command line arguments to 114 | connect the host ssh-agent ports to the ssh-agent ports inside the container. 115 | 116 | ``` 117 | docker run -ti \ 118 | -v $HOME/Work/zephyrproject:/workdir \ 119 | --mount type=bind,src=$SSH_AUTH_SOCK,target=/run/host-services/ssh-auth.sock \ 120 | --env SSH_AUTH_SOCK="/run/host-services/ssh-auth.sock" \ 121 | devel: 122 | ``` 123 | 124 | ### Usage 125 | 126 | #### Building a sample application 127 | 128 | Follow the steps below to build and run a sample application: 129 | 130 | ``` 131 | west build -b qemu_x86 samples/hello_world 132 | west build -t run 133 | ``` 134 | 135 | #### Building display sample applications 136 | 137 | It is possible to build and run the _native POSIX_ sample applications that produce display outputs 138 | by connecting to the Docker instance using a VNC client. 139 | 140 | In order to allow the VNC client to connect to the Docker instance, the port 5900 needs to be 141 | forwarded to the host: 142 | 143 | ``` 144 | docker run -ti -p 5900:5900 -v :/workdir zephyr-build:v 145 | ``` 146 | 147 | Follow the steps below to build a display sample application for the _native POSIX_ board: 148 | 149 | ``` 150 | west build -b native_posix samples/subsys/display/cfb 151 | west build -t run 152 | ``` 153 | 154 | The application display output can be observed by connecting a VNC client to _localhost_ at the 155 | port _5900_. The default VNC password is _zephyr_. 156 | 157 | On a Ubuntu host, this can be done by running the following command: 158 | 159 | ``` 160 | vncviewer localhost:5900 161 | ``` 162 | -------------------------------------------------------------------------------- /bash_completion: -------------------------------------------------------------------------------- 1 | for bcfile in ~/.bash_completion.d/* ; do 2 | . $bcfile 3 | done 4 | 5 | 6 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SNUM=$(echo $DISPLAY | sed 's/:\([0-9][0-9]*\)/\1/') 4 | xvfb-run -n $SNUM -s "-screen 0 1024x768x24" -f ~/.Xauthority openbox-session & 5 | sleep 1 6 | x11vnc -display $DISPLAY -usepw -forever -quiet & 7 | 8 | exec "$@" 9 | --------------------------------------------------------------------------------