diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml new file mode 100644 index 00000000..e3235a4e --- /dev/null +++ b/.github/workflows/docker-publish.yaml @@ -0,0 +1,143 @@ +# Publish the sbsim container image when a GitHub release is published. +# +# Required configuration +# ---------------------- +# No repository secrets are required for the GitHub Container Registry (GHCR) +# publish. The workflow authenticates with the automatically provided +# `GITHUB_TOKEN` and the `packages: write` permission declared below. +# +# Repository administrators should verify that Actions can create packages and +# that the published package is visible to end users. New packages are private +# by default; set `ghcr.io/google/sbsim` to public under the package settings if +# anonymous pulls should be allowed. See: +# - https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry +# - https://docs.github.com/en/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility +# +# Optional Docker Hub publishing +# ------------------------------ +# To also publish `/sbsim` to Docker Hub, configure both repository +# secrets under Settings > Secrets and variables > Actions > Secrets: +# - DOCKER_HUB_USERNAME: Docker Hub username that owns the target repository. +# - DOCKER_HUB_PASSWORD: Docker Hub access token (not the account password) +# with permission to push to the target repository. +# If either secret is unset, the Docker Hub steps are skipped and only GHCR is +# published. See: +# - https://docs.docker.com/security/for-developers/access-tokens/ +# - https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions +# +# Workflow environment variables +# ------------------------------ +# - REGISTRY: registry host for the required GHCR publish (`ghcr.io`). +# - IMAGE_NAME: image path within the registry (`github.repository`, which is +# `google/sbsim` for this repository). +# - DOCKER_HUB_USERNAME and DOCKER_HUB_PASSWORD: optional secrets mapped to +# environment variables so the Docker Hub steps can be skipped when they are +# not configured. Values are masked by GitHub Actions and are never printed. +# +# Image tags +# ---------- +# - Release published: `latest`, the release tag, and, for semantic version +# tags such as `v1.2.3`, `1.2.3` and `1.2`. Non-semver release tags (for +# example `pre-sync-20250521`) still publish the release tag and `latest`. +# - Manual workflow run: the optional `tag` input, or `sha-` when no +# tag is provided. +# +# This workflow only reads repository contents and writes packages. It does not +# modify releases or any other repository state. +name: Docker Publish + +on: + release: + types: + - published + workflow_dispatch: + inputs: + tag: + description: 'Tag for the published image (defaults to sha-)' + required: false + type: string + +permissions: + contents: read + +jobs: + docker-publish: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + - name: Log in to the GitHub Container Registry + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=tag,enable=${{ github.event_name == 'release' }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag != '' }} + type=sha,format=short,enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag == '' }} + + - name: Build and push to the GitHub Container Registry + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=ghcr + cache-to: type=gha,mode=max,scope=ghcr + + - name: Log in to Docker Hub + if: ${{ env.DOCKER_HUB_USERNAME != '' && env.DOCKER_HUB_PASSWORD != '' }} + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + username: ${{ env.DOCKER_HUB_USERNAME }} + password: ${{ env.DOCKER_HUB_PASSWORD }} + + - name: Extract Docker Hub metadata + id: meta-dockerhub + if: ${{ env.DOCKER_HUB_USERNAME != '' && env.DOCKER_HUB_PASSWORD != '' }} + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 + with: + images: ${{ env.DOCKER_HUB_USERNAME }}/sbsim + tags: | + type=ref,event=tag,enable=${{ github.event_name == 'release' }} + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag != '' }} + type=sha,format=short,enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag == '' }} + + - name: Build and push to Docker Hub + if: ${{ env.DOCKER_HUB_USERNAME != '' && env.DOCKER_HUB_PASSWORD != '' }} + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ steps.meta-dockerhub.outputs.tags }} + labels: ${{ steps.meta-dockerhub.outputs.labels }} + cache-from: type=gha,scope=dockerhub + cache-to: type=gha,mode=max,scope=dockerhub diff --git a/README.md b/README.md index d0c57ffe..7ad1731a 100644 --- a/README.md +++ b/README.md @@ -54,14 +54,20 @@ instructions linked below. The [Setup Guide](docs/setup.md) provides all the information you need to run the code locally. +## Docker + +The [Docker Setup Guide](docs/setup/docker.md) explains how to run the image +published to the GitHub Container Registry or build the image locally. + ## Contributing The [Contributor's Guide](docs/contributing.md) provides more information on how to contribute to this repository. -We appreciate contributions and interest from the community! Please note that our -team maintains this repository alongside active internal Google project commitments, -so pull request reviews may take anywhere from a few days to a couple of weeks. -We review PRs as maintainer bandwidth allows. Thank you for your patience and support! +We appreciate contributions and interest from the community! Please note that +our team maintains this repository alongside active internal Google project +commitments, so pull request reviews may take anywhere from a few days to a +couple of weeks. We review PRs as maintainer bandwidth allows. Thank you for +your patience and support! ## [License](LICENSE) diff --git a/docs/setup/docker.md b/docs/setup/docker.md index 3bbbccec..ee834708 100644 --- a/docs/setup/docker.md +++ b/docs/setup/docker.md @@ -1,10 +1,65 @@ # Docker Setup Guide +The repository's `Dockerfile` defines a pre-configured environment +(`linux/amd64`) for running the notebooks and scripts without installing the +dependencies on the host machine. + +You can either run the image published to the GitHub Container Registry or build +the image locally from source. + +## Run the Published Image + +Docker Desktop or Docker Engine must be installed first; see +[Prerequisites](#prerequisites) below. + +A container image is published to the GitHub Container Registry each time a +release is published. Pull the latest image: + +```bash +docker pull --platform linux/amd64 ghcr.io/google/sbsim:latest +``` + +Run the container: + +```bash +docker run -d \ + --name sbsim-container \ + --platform linux/amd64 \ + -p 8888:8888 \ + ghcr.io/google/sbsim:latest +``` + +The image starts a Jupyter notebook server on port 8888 with token +authentication disabled (as configured by the `Dockerfile`). Open your browser +at: + +``` +http://localhost:8888 +``` + +Images are tagged with `latest` and the release tag. For semantic version tags +(for example `v1.2.3`), the `1.2.3` and `1.2` tags are also published. Pin a +specific tag instead of `latest` when you need a reproducible environment: + +```bash +docker pull --platform linux/amd64 ghcr.io/google/sbsim:1.2.3 +``` + +> **Note:** The GitHub Container Registry package must be public for anonymous +> pulls. If it is private, authenticate first with `docker login ghcr.io` using +> a GitHub personal access token that has the `read:packages` scope. + +To open a shell in the running container, use the same `docker exec` commands as +in the [local build section](#exec-into-the-running-container) below. To remove +the published image, run `docker rmi ghcr.io/google/sbsim:latest`. + +## Build the Image Locally + To get the repository set up on **non-Linux** environments (e.g. macOS on Apple Silicon), use the pre-configured Docker environment (`linux/amd64`) defined in the `Dockerfile`. -## 1. Prerequisites +### Prerequisites 1. **Docker Desktop**: Download and install from [docker.com](https://www.docker.com/products/docker-desktop). @@ -27,9 +82,7 @@ If `hello-world` succeeds, you're ready to proceed. > workloads may crash or hang due to resource constraints. For heavy TF > workloads, consider using a native Linux environment or cloud-based compute. -______________________________________________________________________ - -## 2. Build the Docker Image +### Build the Docker Image From the project root (where `Dockerfile` lives), run: @@ -51,9 +104,7 @@ Confirm the image exists: docker images sbsim:latest ``` -______________________________________________________________________ - -## 3. Run the Container in Detached Mode +### Run the Container in Detached Mode We recommend running the container _detached_ so you can open shells, run tests, and launch Jupyter without tying up your terminal: @@ -69,7 +120,7 @@ docker run -d \ > **Note:** This mounts your local code into `/workspace` in the container, > enabling live edits. -### 3.1 Access Jupyter +### Access Jupyter Open your browser at: @@ -84,9 +135,7 @@ deprecation warning for `NotebookApp.token`, you can instead use: jupyter notebook --no-browser --ServerApp.token='' ``` -______________________________________________________________________ - -## 4. Exec into the Running Container +### Exec into the Running Container To run commands inside the live container: @@ -122,9 +171,7 @@ docker exec sbsim-container poetry run pytest -q docker exec sbsim-container python --version ``` -______________________________________________________________________ - -## 5. Stop & Clean Up +### Stop and Clean Up ```bash # Stop the container @@ -137,9 +184,7 @@ docker rm sbsim-container docker rmi sbsim:latest ``` -______________________________________________________________________ - -## 6. Troubleshooting +### Troubleshooting - **Daemon not running**: If you see `Cannot connect to the Docker daemon`, open Docker Desktop or run: