Examples
💡 Click on the heading to expand/collapse the item.
Steps
Deploy from the repository
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}Deploy from a compose file
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
type: fileDeploy from a different repository
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
repo: https://github.com/user/some-other-repo
ref: refs/heads/masterSpecify environment variables
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
env_json: '{"KEY": "Value"}'
env_file: .envMerging existing environment variables
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
env_json: '{"KEY": "Value"}'
merge_env: trueMultiline JSON data input
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
env_json: |
{
"APP_PRIVATE_KEY": "${{ secrets.APP_PRIVATE_KEY }}",
"VERSION": "${{ inputs.VERSION }}"
}Only run on release events
This is done by setting: if: ${{ github.event_name == 'release' }}
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
if: ${{ github.event_name == 'release' }}
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}Add Cloudflare Zero Trust service token headers
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
headers: |
{
"CF-Access-Client-Id": "${{ secrets.CF_CLIENT_ID }}",
"CF-Access-Client-Secret": "${{ secrets.CF_CLIENT_SECRET }}"
}Deploy with relative path volumes Business Edition
yaml
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
fs_path: /mntTrigger a Portainer Webhook Service Webhook
yaml
- name: "Portainer Webhook"
uses: cssnr/web-request-action@v1
with:
url: ${{ secrets.PORTAINER_WEBHOOK }}This uses: cssnr/web-request-action
Multi-Step
Use Output with toJSON - hashicorp/vault-action
yaml
- name: "Import Secrets"
id: import-secrets
uses: hashicorp/vault-action@v2
with:
url: https://vault.mycompany.com:8200
token: ${{ secrets.VAULT_TOKEN }}
caCertificate: ${{ secrets.VAULT_CA_CERT }}
secrets: |
secret/data/ci/aws accessKey | AWS_ACCESS_KEY_ID ;
secret/data/ci/aws secretKey | AWS_SECRET_ACCESS_KEY ;
secret/data/ci npm_token
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
name: "stack-name"
file: "docker-compose.yaml"
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
env_json: ${{ toJSON(steps.import-secrets.outputs) }}Workflows
Workflow Run and Dispatch Trigger
This uses the workflow_run trigger and an if: condition to only run after the job named Build is successful, while also allowing you to manually deploy any version you choose.
yaml
name: "Deploy"
on:
workflow_dispatch:
inputs:
version:
description: "Version Tag"
default: "latest"
required: false
workflow_run:
workflows: ["Build"]
types: [completed]
env:
traefik-host: badges.cssnr.com
stack-file: docker-compose-swarm.yaml
stack-name: ${{ github.repository_owner }}-${{ github.event.repository.name }}
version: ${{ inputs.version || github.event.workflow_run.head_branch || github.ref_name }}
jobs:
deploy:
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
name: "Deploy"
runs-on: ubuntu-latest
timeout-minutes: 5
environment:
name: swarm
url: https://badges.cssnr.com/
steps:
- name: "Debug Variables"
continue-on-error: true
run: |
echo "VERSION: ${{ env.version == 'master' && 'latest' || env.version }}"
echo "STACK_NAME: ${{ env.stack-name }}"
echo "TRAEFIK_HOST: ${{ env.traefik-host }}"
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
file: ${{ env.stack-file }}
name: ${{ env.stack-name }}
username: ${{ vars.GHCR_USER }}
password: ${{ secrets.GHCR_PASS }}
env_json: |
{
"VERSION": "${{ env.version == 'master' && 'latest' || env.version }}",
"STACK_NAME": "${{ env.stack-name }}",
"TRAEFIK_HOST": "${{ env.traefik-host }}"
}Full Workflow Example
This combines a build, deploy, and cleanup into a single job.
yaml
name: "Portainer Stack Deploy"
on:
workflow_dispatch:
inputs:
tags:
description: "Tags: comma,separated"
required: true
default: "latest"
release:
types: [published]
env:
registry: ghcr.io
stack-file: docker-compose-swarm.yaml
stack-name: ${{ github.repository_owner }}-${{ github.event.repository.name }}
version: ${{ github.ref_name == 'master' && 'latest' || github.ref_name }}
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
jobs:
build:
name: "Build"
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
packages: write
steps:
- name: "Checkout"
uses: actions/checkout@v5
- name: "Debug Variables"
continue-on-error: true
run: |
echo "VERSION: ${{ env.version == 'master' && 'latest' || env.version }}"
echo "STACK_NAME: ${{ env.stack-name }}"
- name: "Docker Login"
uses: docker/login-action@v3
with:
registry: ${{ env.registry }}
username: ${{ vars.GHCR_USER }}
password: ${{ secrets.GHCR_PASS }}
- name: "Setup Buildx"
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: "Generate Docker Tags"
id: tags
uses: cssnr/docker-tags-action@v1
with:
images: $${{ env.registry }}/${{ github.repository }}
tags: ${{ inputs.tags }}
- name: "Debug Docker Tags"
continue-on-error: true
run: |
echo "github.ref_name: ${{ github.ref_name }}"
echo "tags: ${{ steps.tags.outputs.tags }}"
echo "labels: ${{ steps.tags.outputs.labels }}"
echo "annotations: ${{ steps.tags.outputs.annotations }}"
- name: "Build and Push"
uses: docker/build-push-action@v6
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.tags.outputs.tags }}
labels: ${{ steps.tags.outputs.labels }}
annotations: ${{ steps.tags.outputs.annotations }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.ref_name }}
deploy:
name: "Deploy"
runs-on: ubuntu-latest
timeout-minutes: 5
needs: build
steps:
- name: "Checkout"
uses: actions/checkout@v5
- name: "Portainer Deploy"
uses: cssnr/portainer-stack-deploy-action@v1
with:
url: ${{ secrets.PORTAINER_URL }}
token: ${{ secrets.PORTAINER_TOKEN }}
file: ${{ env.stack-file }}
name: ${{ env.stack-name }}
username: ${{ vars.GHCR_USER }}
password: ${{ secrets.GHCR_PASS }}
env_json: |
{
"VERSION": "$${{ github.ref_name }}",
"STACK_NAME": "${{ env.stack-name }}",
}
cleanup:
name: "Cleanup"
runs-on: ubuntu-latest
timeout-minutes: 5
needs: deploy
steps:
- name: "Purge Cache"
uses: cssnr/cloudflare-purge-cache-action@v2
with:
token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
zones: cssnr.comFor more examples, you can check out other projects using this action:
https://github.com/cssnr/portainer-stack-deploy-action/network/dependents
Get Help
If you have more questions, please request support
