7.3 KiB
Building an Image for Container Registries
Sometimes you may need to have a custom version of the dashboard that is packaged alongside Rancher to be hosted within Github's container registry. There are a few use cases for this, for instance when developing a package/product for Rancher that doesn't need to be standalone or when it isn't necessary for the package to exist in the Dashboard by default.
Prerequisites
- A branch on the Dashboard repo to store the custom dashboard
- A target repository where the dashboard will be added as a submodule
- Access to the target repository actions with a PAT to authenticate from within the action
Steps
1. Add branched repo as a submodule
Run the following to add a submodule to your target repo:
git submodule add <branch-repo-path>
This will generate a config file .gitmodules in the root directory, it will contain the path of the submodule and the url of the repo. In order to target a specific branch you will need to add a branch property to this file. For instance:
[submodule "dashboard"]
path = dashboard
url = https://github.com/rancher/dashboard.git
branch = <target-branch>
Push these changes to the target repo and you will now see the submodule with the path you specified in .gitmodules.
2. Create Dockerfile to build Rancher image
Create a new Dockerfile in your branched repo that will build both the frontend from your branch and the main Rancher image. It will need to replace the dashboard files in the Rancher image with the build from the new frontend.
# /Dockerfile.example
FROM node:lts AS builder
WORKDIR /src
COPY . .
RUN yarn --pure-lockfile install
ENV ROUTER_BASE="/dashboard"
RUN yarn run build --spa
FROM rancher/rancher:v2.6.3
WORKDIR /var/lib/rancher
RUN rm -rf /usr/share/rancher/ui-dashboard/dashboard*
COPY --from=builder /src/dist /usr/share/rancher/ui-dashboard/dashboard
This will build the frontend from your branch with RUN yarn run build --spa and replace the dashboard in the Rancher image with COPY --from=builder /src/dist /usr/share/rancher/ui-dashboard/dashboard.
3. Create action to dispatch the image
In order to make publishing the new package to the Github Registry automatic you will need to create an action that will build the new Rancher image from your submodule's Dockerfile and dispatch the image into a package.
Create two new directories in your target repo:
/.github/workflows
Add a new YAML file in the workflow directory:
# /.github/workflows/build-image.yml
name: Dispatch Dashboard image
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }} # The target repo
jobs:
build:
name: Build Dashboard image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
token: ${{ secrets.WORKFLOW_PAT }} # The PAT referenced in prerequisites
submodules: recursive # If the repo has multiple submodules to checkout
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} # This is the repo owner
password: ${{ secrets.GITHUB_TOKEN }} # A token generated during the workflow
- name: Build and push Dashboard image
uses: docker/build-push-action@v2
with:
context: ./dashboard # Context for docker to find the Dockerfile in the submodule
file: ./dashboard/Dockerfile.example # Dockerfile you created
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
We are using docker/build-push-action@v2 to do the heavy lifting for us. This file will create a new package any time a push or pull request is made on the main branch. It first provides a platform for which to build the image that has permissions to read contents and write packages. We're using ubuntu-latest in this case.
The steps laid out are mostly self-explanatory, it will first checkout the repository with the given secrets.WORKFLOW_PAT you created in the prerequisites. The steps for setting up QEMU and Docker Buildx are recommened by the docker/build-push-action.
The final two steps are where the magic happens. First logging into the Github Container Registry with a temporary GITHUB_TOKEN, then building and pushing the actual image to be packaged.
Running the custom build
When running your newly built image Rancher will need to know to serve the "locally" installed dashboard. You can do this by setting the CATTLE_UI_DASHBOARD_INDEX environment variable in your docker run command.
For instance:
docker run -d --name dashboard \
--restart=unless-stopped \
--privileged \
-p 80:80 -p 443:443 \
-e CATTLE_UI_DASHBOARD_INDEX=https://localhost/dashboard/index.html \
ghcr.io/<example-repo>:latest
Troubleshooting
At the time of writing (February '22), the build time for the Dashboard frontend and Rancher image takes about 8 minutes, so some debugging in place will greatly diminish any frustration while building an action.
The simplest way of adding debugging to your action is by enabling runner diagnostic logging. You can do this by adding an environment variable to the beginning of your workflow action ACTIONS_RUNNER_DEBUG: true
For instance:
# /.github/workflows/build-image.yml
...
env:
ACTIONS_RUNNER_DEBUG: true
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
...
This way can be a little verbose but can help narrow down which step is causing you trouble. If you want to see the logs for a specific step you can add an environment variable to your step: ACTIONS_STEP_DEBUG: true
For instance:
# /.github/workflows/build-image.yml
...
- name: Build and push dashboard image
uses: docker/build-push-action@v2
env:
ACTIONS_STEP_DEBUG: true
with:
context: ./dashboard
...
Some actions have unique debugging features that you can utilize container logs to see what is happening behind the scenes. In our build-image.yml example we are using docker/setup-buildx-action which has logs you can access.
Caveats
With docker/build-push-action there are a few caveats that could cause confusion. Be sure that your repository name is lowercase!