Running Commodore

Commodore is written in Python and it requires external dependencies. We provide Commodore as a container image and a Python package on PyPI.

For local development, the procedure is documented in the README.

Commodore interacts with Git repositories that might require authorization. For this to work, Commodore needs to have access to an authorized SSH key.

PyPI

We recommend that you use the Commodore Python package provided on PyPI to make commodore available locally.

Prerequisites

  • A Python version between 3.8 and 3.11 as python3 and the Python venv module. We recommend that you install Python and the venv module with your preferred package manager.

  • Additionally, a few of the Commodore Python package dependencies require a working C compiler, the Python 3 development package, and the FFI development package. On Linux distributions you’ll want packages python3-dev or python3-devel and libffi-dev or libffi-devel respectively. Please refer to your operating system’s documentation for instructions to setup a working C compiler.

  • On some Linux distributions, you may need to install the Python wheel package manually.

  • jsonnet-bundler from projectsyn/jsonnet-bundler/releases in your $PATH as jb.

  • Helm 3, installation instructions

  • kustomize, some components might require Kustomize. Versions >= 4 are recommended. Installation instructions

Other documentation assumes that Helm 3 is available as helm and helm3, and Helm 2 is available as helm2 in $PATH. Please make sure you setup the Helm binaries accordingly on your local system.

Installation

Generally, it’s best to create a separate virtualenv for Python utilities. Having separate virtualenvs avoids running into dependency conflicts when installing multiple Python utilities from PyPI.

  1. Check your Python version

    python3 --version

    This command should report something like

    Python 3.8.10
  2. Create a virtualenv in ~/.local/commodore-venv

    python3 -m venv ~/.local/commodore-venv
  3. Activate the virtualenv

    source ~/.local/commodore-venv/bin/activate
  4. Install Commodore into the virtualenv

    pip install syn-commodore
  5. On MacOS you’ll also need libmagic via brew

    brew install libmagic
  6. Check that commodore was installed correctly

    commodore --version
  7. Finally, patch Kapitan to use reclass-rs over the bundled Python implementation. This significantly improves compilation times of Commodore cluster catalogs.

    KAPITAN_PATH=$(python -c 'import kapitan; print(kapitan.__path__[0])')
    curl -L \
      https://raw.githubusercontent.com/projectsyn/reclass-rs/main/hack/kapitan_0.32_reclass_rs.patch \
      | patch -p1 -d "${KAPITAN_PATH}"

    The reclass-rs Python package is installed automatically as a dependency of Commodore. For officially supported platforms (Linux, macOS), prebuilt wheels are available on PyPI.

    This step is optional, but we highly recommend using reclass-rs over Kapitan’s bundled Reclass implementation.

    We’re actively working with Kapitan to upstream support for reclass-rs, so this step may disappear again in future versions of this page.

Usage

If you’ve installed Commodore into a virtualenv, you either need to activate the virtualenv whenever you want to run Commodore, or you can create a symlink to the commodore entrypoint script in a directory which is part of your $PATH.

You might need to change your git configuration so that the .git/config.lock file gets created with the correct permissions: git config --global core.filemode false

This section assumes that you’ve added ~/.local/bin to your $PATH. If you use another directory, you can adjust the commands in this section as needed.

Create a symlink to the commodore entrypoint script in ~/.local/bin.

ln -s ~/.local/commodore-venv/bin/commodore ~/.local/bin/

After that, you can run Commodore with

commodore --help
We recommend this approach, especially if you’re interested in using shell completion for Commodore.

Activating the virtualenv

source ~/.local/commodore-venv/bin/activate

After that, you can run Commodore with

commodore --help
To leave the virtualenv, you can execute the deactivate command.

Docker

If you want, you can also use the Commodore container image locally.

In that case, the following shell functions can be placed in your shells configuration file (for example ~/.profile, ~/.bashrc, .zshrc etc.). By doing so, you can run commodore as if it was any other executable on your system.

Linux

On Linux it’s possible to use SSH agent and mounting the agents socket into the container.

commodore() {
  local pubring="${HOME}/.gnupg/pubring.kbx"
  if command -v gpgconf &>/dev/null && test -f "${pubring}"; then
    gpg_opts=(--volume "${pubring}:/app/.gnupg/pubring.kbx:ro" --volume "$(gpgconf --list-dir agent-extra-socket):/app/.gnupg/S.gpg-agent:ro")
  else
    gpg_opts=
  fi

  docker run \
    --interactive=true \
    --tty \
    --rm \
    --user="$(id -u)" \
    --env COMMODORE_API_URL=$COMMODORE_API_URL \
    --env COMMODORE_API_TOKEN=$COMMODORE_API_TOKEN \
    --env SSH_AUTH_SOCK=/tmp/ssh_agent.sock \
    --publish 18000:18000 \
    --volume "${SSH_AUTH_SOCK}:/tmp/ssh_agent.sock" \
    --volume "${HOME}/.ssh/config:/app/.ssh/config:ro" \
    --volume "${HOME}/.ssh/known_hosts:/app/.ssh/known_hosts:ro" \
    --volume "${HOME}/.gitconfig:/app/.gitconfig:ro" \
    --volume "${HOME}/.cache:/app/.cache" \
    ${gpg_opts[@]} \
    --volume "${PWD}:${PWD}" \
    --workdir "${PWD}" \
    projectsyn/commodore:${COMMODORE_VERSION:=latest} \
    $*
}

We mount the current working directory on the host (${PWD}) to the same directory in the container. This is necessary to ensure that commands such as catalog compile and component new create Git repository checkouts which work both in the container and on the host.

macOS

On macOS with Docker for Mac mounting the SSH agents socket into a container doesn’t work. Instead you need to mount as magic path that’s provided by Docker for Mac.

This only works for the stock ssh-agent coming along with macOS. If you use any other agent, you might be out of luck. Docker for mac doesn’t support mounting sockets.

That magic socket path belongs to root. One must run a container with --user=0 in order to access it. This doesn’t mess up your file permissions thanks to the magic of how volume mount work on Docker for Mac.

commodore() {
  docker run \
    --interactive=true \
    --tty \
    --rm \
    --user="0" \
    --env COMMODORE_API_URL=$COMMODORE_API_URL \
    --env COMMODORE_API_TOKEN=$COMMODORE_API_TOKEN \
    --env SSH_AUTH_SOCK=/tmp/ssh_agent.sock \
    --publish 18000:18000 \
    --volume "/run/host-services/ssh-auth.sock:/tmp/ssh_agent.sock" \
    --volume "${HOME}/.ssh/config:/app/.ssh/config:ro" \
    --volume "${HOME}/.ssh/known_hosts:/app/.ssh/known_hosts:ro" \
    --volume "${HOME}/.gitconfig:/app/.gitconfig:ro" \
    --volume "${HOME}/.cache:/app/.cache" \
    --volume "${PWD}:${PWD}" \
    --workdir "${PWD}" \
    projectsyn/commodore:latest \
    $*
}

We mount the current working directory on the host (${PWD}) to the same directory in the container. This is necessary to ensure that commands such as catalog compile and component new create Git repository checkouts which work both in the container and on the host.

Instead you can also mount your SSH key into the container. The container will pickup that key and add it do an SSH agent running inside the container. You will be prompted to insert your SSH keys password if it has one.

commodore() {
  docker run \
    --interactive=true \
    --tty \
    --rm \
    --user="$(id -u)" \
    --env COMMODORE_API_URL=$COMMODORE_API_URL \
    --env COMMODORE_API_TOKEN=$COMMODORE_API_TOKEN \
    --publish 18000:18000 \
    --volume "${HOME}/.ssh:/app/.ssh:ro" \
    --volume "${HOME}/.gitconfig:/app/.gitconfig:ro" \
    --volume "${HOME}/.cache:/app/.cache" \
    --volume "${PWD}:${PWD}" \
    --workdir "${PWD}" \
    projectsyn/commodore:latest \
    $*
}

If you have multiple SSH keys, you can mount only the one you need for commodore. This will remove the password prompt for each and every SSH key. Do this by using the following volumes instead of the line --volume "${HOME}/.ssh:/app/.ssh:ro" \

    --volume "${HOME}/.ssh/config:/app/.ssh/config:ro" \
    --volume "${HOME}/.ssh/known_hosts:/app/.ssh/known_hosts:ro" \
    --volume "/path/to/your/key:/app/.ssh/id_rsa:ro" \ (1)
1 Replace /path/to/your/key according to your needs.