Skip to content

Easily Deploy a Docker Swarm or Compose Stack to a Remote Docker Host over SSH, with Keyfile or Password Authentication.

License

Notifications You must be signed in to change notification settings

cssnr/stack-deploy-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

GitHub Tag Major GitHub Tag Minor GitHub Release Version Workflow Release Workflow Test Workflow Lint GitHub Last Commit Codeberg Last Commit Docs Last Commit GitHub Contributors GitHub Repo Size GitHub Top Language GitHub Discussions GitHub Forks GitHub Repo Stars GitHub Org Stars Discord Ko-fi

Docker Stack Deploy Action

Tip

▶️ View the Getting Started Guide on the website.

Easily Deploy a Docker Swarm or Compose Stack, from a compose file, to a remote Docker host over SSH, with keyfile or password authentication.

Deploy directly from the actions working directory without copying any files using a remote Docker context. This allows you to easily prepare your environment for deployment using normal steps.

Supports many features including authenticating against a private registry, deploying multiple stack files, setting custom arguments, and much more.

- name: 'Stack Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name' # set to your stack name
    file: 'docker-compose.yaml' # set to your compose file
    host: ${{ secrets.DOCKER_HOST }}
    user: ${{ secrets.DOCKER_USER }}
    port: 22 # 22 is default, you can remove or change this
    pass: ${{ secrets.DOCKER_PASS }} # not needed with ssh_key
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }} # not needed with pass
    mode: swarm # if not using swarm set to: compose

Make sure to review the Inputs, available Tags and additional Examples.

Portainer Users: You can deploy directly to Portainer with: cssnr/portainer-stack-deploy-action

Features

  • Deploy to Docker Swarm or Compose.
  • Deploy over SSH using keyfile or password.
  • Deploy from the current working directory.
  • Deploy from a private registry with credentials.
  • Job Summary with deployment output, including errors.
  • Supports multiple compose file and stack deployments.
  • Allows setting custom arguments for the deployment command.
  • View more the Features on the website.

Don't see your feature here? Please help by submitting a Feature Request.

Inputs

Important

View the Inputs Documentation for comprehensive, up-to-date documentation.

Input Name Required Default Value Short Description of the Input Value
name Yes - Docker Stack/Project Name *
file - docker-compose.yaml Docker Stack/Compose File(s) *
mode¹ - swarm Deploy Mode [swarm, compose] *
args¹ - --remove-orphans --force-recreate Additional Compose Arguments *
host Yes - Remote Docker Hostname or IP *
port - 22 Remote Docker Port
user Yes - Remote Docker Username
pass or ssh_key - Remote Docker Password *
ssh_key or pass - Remote SSH Key File *
disable_keyscan - false Disable SSH Keyscan ssh-keyscan *
env_file - - Docker Environment File *
detach² - true Detach Flag, false, to disable *
prune² - false Prune Flag, true, to enable
resolve_image² - always Resolve [always, changed, never] *
registry_auth² - false Enable Registry Authentication *
registry_host - - Registry Authentication Host *
registry_user - - Registry Authentication Username *
registry_pass - - Registry Authentication Password *
summary - true Add Job Summary *

¹ Compose Only, view the Docs.
² Swarm Only, view the Docs.
* More details below...

📟 Click Here to see how the deployment command is generated
if [[ "${INPUT_MODE}" == "swarm" ]];then
    DEPLOY_TYPE="Swarm"
    COMMAND=("docker" "stack" "deploy" "-c" "${INPUT_FILE}" "${EXTRA_ARGS[@]}" "${INPUT_NAME}")
else
    DEPLOY_TYPE="Compose"
    COMMAND=("docker" "compose" "${STACK_FILES[@]}" "-p" "${INPUT_NAME}" "up" "-d" "-y" "${EXTRA_ARGS[@]}")
fi

Compose Note: "${STACK_FILES[@]}" is an array of -f docker-compose.yaml for every file in the argument.


name: Stack name for Swarm and project name for Compose.

file: Stack file or Compose file(s). Multiple files can be provided, space seperated, and a -f will be prepended to each. Example: web.yaml db.yaml.

mode: Compose only. Set this to compose to use compose up instead of stack deploy for non-swarm hosts.

args: Compose only. Compose arguments to pass to the compose up command. Only used for mode: compose deployments. The detach flag defaults to false for compose. With no args the default is --remove-orphans --force-recreate. Use an empty string to override. For more details, see the compose docs.

host: The hostname or IP address of the remote docker server to deploy too. If your hostname is behind a proxy like Cloudflare you will need to use the IP address.

pass/ssh_key: You must provide either a pass or ssh_key, not both.

disable_keyscan: This will disable the ssh-keyscan command. Advanced use only.

env_file: Variables in this file are exported before running stack deploy. To use a docker env_file specify it in your compose file and make it available in a previous step. If you need compose file templating this can also be done in a previous step. If using mode: compose you can also add the compose_arg: --env-file stringArray.

detach: Swarm only. Set this to false to not exit immediately and wait for the services to converge. This will generate extra output in the logs and is useful for debugging deployments. Defaults to false in mode: compose.

resolve_image: Swarm only. When the default always is used, this argument is omitted.

registry_auth: Swarm only. Set to true to deploy with --with-registry-auth.

registry_host: To run docker login on another registry. Example: ghcr.io.

registry_user/registry_pass: Required to run docker login before stack deploy.

summary: Write a Summary for the job. To disable this set to false.

To view a workflow run, click on a recent Test job (requires login).

👀 View Example Successful ✔️ Job Summary

🚀 Swarm Stack test_stack-deploy Successfully Deployed.

docker stack deploy -c docker-compose.yaml --detach=false --resolve-image=changed test_stack-deploy
Results
Updating service test_stack-deploy_alpine (id: tdk8v42m0rvp9hz4rbfrtszb6)
1/1:
overall progress: 0 out of 1 tasks
overall progress: 1 out of 1 tasks
verify: Waiting 5 seconds to verify that tasks are stable...
verify: Waiting 4 seconds to verify that tasks are stable...
verify: Waiting 3 seconds to verify that tasks are stable...
verify: Waiting 2 seconds to verify that tasks are stable...
verify: Waiting 1 seconds to verify that tasks are stable...
verify: Service tdk8v42m0rvp9hz4rbfrtszb6 converged

👀 View Example Failure ❌ Job Summary

⛔ Swarm Stack test_stack-deploy Failed to Deploy!

docker stack deploy -c docker-compose.yaml --detach=false --resolve-image=changed test_stack-deploy
Errors
Creating network test_stack-deploy_default
failed to create network test_stack-deploy_default: Error response from daemon: network with name test_stack-deploy_default already exists

- name: 'Stack Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name' # set to your stack name
    file: 'docker-compose.yaml' # set to your compose file
    host: ${{ secrets.DOCKER_HOST }}
    user: ${{ secrets.DOCKER_USER }}
    port: 22 # 22 is default, you can remove or change this
    pass: ${{ secrets.DOCKER_PASS }} # not needed with ssh_key
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }} # not needed with pass
    mode: swarm # if not using swarm set to: compose

Examples

Additional Examples are available on the website.

💡 Click on an example heading to expand or collapse the example.

With Password, docker login and --with-registry-auth
- name: 'Stack Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose-swarm.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    pass: ${{ secrets.DOCKER_PASS }}
    registry_host: 'ghcr.io'
    registry_user: ${{ vars.GHCR_USER }}
    registry_pass: ${{ secrets.GHCR_PASS }}
With SSH Key, --prune, --detach=false and --resolve-image=changed
- name: 'Stack Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose-swarm.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }}
    detach: false
    prune: true
    resolve_image: 'changed'
With All Swarm Inputs
- name: 'Stack Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose-swarm.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    pass: ${{ secrets.DOCKER_PASS }} # not needed with ssh_key
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }} # not needed with pass
    env_file: 'stack.env'
    detach: true
    prune: false
    resolve_image: 'always'
    registry_auth: true # not needed with registry_pass/registry_user
    registry_host: 'ghcr.io'
    registry_user: ${{ vars.GHCR_USER }}
    registry_pass: ${{ secrets.GHCR_PASS }}
    summary: true
Compose with Defaults
- name: 'Compose Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }}
    mode: compose
Compose with Custom Arguments
- name: 'Compose Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }}
    mode: compose
    args: --remove-orphans --force-recreate

Note: these are the default arguments. If you use args this will override the default arguments unless they are included. You can disable them by passing an empty string. For more details, see the compose up docs.

Compose with Private Image
- name: 'Compose Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }}
    registry_host: 'ghcr.io'
    registry_user: ${{ vars.GHCR_USER }}
    registry_pass: ${{ secrets.GHCR_PASS }}
    mode: compose
With All Compose Inputs
- name: 'Stack Deploy'
  uses: cssnr/stack-deploy-action@v1
  with:
    name: 'stack-name'
    file: 'docker-compose-swarm.yaml'
    host: ${{ secrets.DOCKER_HOST }}
    port: ${{ secrets.DOCKER_PORT }}
    user: ${{ secrets.DOCKER_USER }}
    pass: ${{ secrets.DOCKER_PASS }} # not needed with ssh_key
    ssh_key: ${{ secrets.DOCKER_SSH_KEY }} # not needed with pass
    env_file: 'stack.env'
    registry_host: 'ghcr.io'
    registry_user: ${{ vars.GHCR_USER }}
    registry_pass: ${{ secrets.GHCR_PASS }}
    mode: compose
    args: --remove-orphans --force-recreate
    summary: true
Simple Workflow Example
name: 'Stack Deploy Action'

on:
  push:

jobs:
  deploy:
    name: 'Deploy'
    runs-on: ubuntu-latest
    timeout-minutes: 5

    steps:
      - name: 'Checkout'
        uses: actions/checkout@v5

      - name: 'Stack Deploy'
        uses: cssnr/stack-deploy-action@v1
        with:
          name: 'stack-name'
          file: 'docker-compose-swarm.yaml'
          host: ${{ secrets.DOCKER_HOST }}
          port: ${{ secrets.DOCKER_PORT }}
          user: ${{ secrets.DOCKER_USER }}
          pass: ${{ secrets.DOCKER_PASS }}
Full Workflow Example
name: 'Stack Deploy Action'

on:
  workflow_dispatch:
    inputs:
      tags:
        description: 'Tags: comma,separated'
        required: true
        default: 'latest'

env:
  REGISTRY: 'ghcr.io'

concurrency:
  group: ${{ github.workflow }}
  cancel-in-progress: true

jobs:
  build:
  name: 'Build'
  runs-on: ubuntu-latest
  timeout-minutes: 15
  permissions:
    packages: write

  steps:
    - name: 'Checkout'
      uses: actions/checkout@v5

    - name: 'Setup Buildx'
      uses: docker/setup-buildx-action@v3
      with:
        platforms: 'linux/amd64,linux/arm64'

    - name: 'Docker Login'
      uses: docker/login-action@v3
      with:
        registry: $${{ env.REGISTRY }}
        username: ${{ secrets.GHCR_USER }}
        password: ${{ secrets.GHCR_PASS }}

    - name: 'Generate Tags'
      id: tags
      uses: cssnr/docker-tags-action@v1
      with:
        images: $${{ env.REGISTRY }}/${{ github.repository }}
        tags: ${{ inputs.tags }}

    - name: 'Build and Push'
      uses: docker/build-push-action@v6
      with:
        context: .
        platforms: 'linux/amd64,linux/arm64'
        push: true
        tags: ${{ steps.tags.outputs.tags }}
        labels: ${{ steps.tags.outputs.labels }}

  deploy:
    name: 'Deploy'
    runs-on: ubuntu-latest
    timeout-minutes: 5
    needs: [build]

    steps:
      - name: 'Checkout'
        uses: actions/checkout@v4

      - name: 'Stack Deploy'
        uses: cssnr/stack-deploy-action@v1
        with:
          name: 'stack-name'
          file: 'docker-compose-swarm.yaml'
          host: ${{ secrets.DOCKER_HOST }}
          port: ${{ secrets.DOCKER_PORT }}
          user: ${{ secrets.DOCKER_USER }}
          ssh_key: ${{ secrets.DOCKER_SSH_KEY }}

  cleanup:
    name: 'Cleanup'
    runs-on: ubuntu-latest
    timeout-minutes: 5
    needs: deploy
    permissions:
      contents: read
      packages: write

    steps:
      - name: 'Purge Cache'
        uses: cssnr/cloudflare-purge-cache-action@v2
        with:
          token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          zones: cssnr.com

For more examples, you can check out other projects using this action:
https://github.com/cssnr/stack-deploy-action/network/dependents

Tags

The following rolling tags are maintained.

Version Tag Rolling Bugs Feat. Name Target Example
GitHub Tag Major Major vN.x.x vN
GitHub Tag Minor Minor vN.N.x vN.N
GitHub Release Micro vN.N.N vN.N.N

You can view the release notes for each version on the releases page.

The Major tag is recommended. It is the most up-to-date and always backwards compatible. Breaking changes would result in a Major version bump. At a minimum you should use a Minor tag.

Support

For general help or to request a feature see:

If you are experiencing an issue/bug or getting unexpected results you can:

For more information, see the CSSNR SUPPORT.md.

Contributing

If you would like to submit a PR, please review the CONTRIBUTING.md.

To contribute to the documentation site go to cssnr/stack-deploy-docs.

Please consider making a donation to support the development of this project and additional open source projects.

Ko-fi

Additionally, you can support other GitHub Actions I have published:

For a full list of current projects visit: https://cssnr.github.io/

About

Easily Deploy a Docker Swarm or Compose Stack to a Remote Docker Host over SSH, with Keyfile or Password Authentication.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

Contributors 3

  •  
  •  
  •