Last active
September 24, 2025 17:42
-
-
Save Wonno/2b9f4229bf08f9cbf52f083d83683564 to your computer and use it in GitHub Desktop.
Portainer: Stack creation via API and local compose.yml and stack.env
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Create Stack in Portainer using API | |
| # | |
| # - compose.yml | |
| # - stack.env | |
| set -euo pipefail | |
| which curl || (echo "Missing 'curl'"; exit 1) | |
| which jq || (echo "Missing 'jq'"; exit 1) | |
| which jo || (echo "Missing 'jo'"; exit 1) | |
| # read values from config file | |
| if [[ -e portainer.config ]] ; then | |
| source portainer.config | |
| fi | |
| if [[ -z "${PORTAINER_USER-}" ]]; then | |
| read -rp "Portainer-User: " PORTAINER_USER | |
| echo | |
| fi | |
| if [[ -z "${PORTAINER_PASSWORD-}" ]]; then | |
| read -srp "Portainer-Password: " PORTAINER_PASSWORD | |
| echo | |
| fi | |
| if [[ -z "${PORTAINER_URL-}" ]]; then | |
| read -rp "Portainer-URL: " PORTAINER_URL | |
| echo | |
| fi | |
| if [[ -z "${PORTAINER_ENDPOINTNAME-}" ]]; then | |
| read -rp "Endpoint-Name: " PORTAINER_ENDPOINTNAME | |
| echo | |
| fi | |
| if [[ -z "${PORTAINER_STACKNAME-}" ]]; then | |
| read -rp "Stack-Name: " PORTAINER_STACKNAME | |
| echo | |
| fi | |
| # Get Bearer Token | |
| PORTAINER_TOKEN=$(curl --silent --fail --show-error \ | |
| --request POST "${PORTAINER_URL}/api/auth" \ | |
| --data "$(jo username="${PORTAINER_USER}" password="${PORTAINER_PASSWORD}")" \ | |
| | jq -r '.jwt') | |
| # Fetch ID by name | |
| PORTAINER_ENDPOINTID=$(curl --silent --fail --show-error \ | |
| --request GET "${PORTAINER_URL}/api/endpoints" \ | |
| --header "Authorization: Bearer ${PORTAINER_TOKEN}" \ | |
| | jq --arg name "${PORTAINER_ENDPOINTNAME}" '.[] | select (.Name==$name).Id ') | |
| declare -A properties | |
| # Read File "stack.env" into associative array; skip empty lines; skip commented lines | |
| while IFS='=' read -r key value; do | |
| properties["$key"]="$value" | |
| done < <( | |
| # shellcheck disable=SC2002 | |
| cat stack.env \ | |
| | tr -s '\n' \ | |
| | grep -Ev "^[[:space:]]*#.*" | |
| ) | |
| # Convert associative array to JSON array with name value pairs | |
| STACKENV=$(for key in "${!properties[@]}"; do | |
| jo -- -s name="${key}" -s value="${properties[$key]}" | |
| done | jo -a -p) | |
| # Create the Portainer stack | |
| curl --silent --fail --show-error \ | |
| --request POST "${PORTAINER_URL}/api/stacks/create/standalone/file" \ | |
| --header 'cookie: wonnoauthenticator=rjs3fsK5L2rA0uV9Aoou;' \ | |
| --header "Authorization: Bearer ${PORTAINER_TOKEN}" \ | |
| --form "Name=${PORTAINER_STACKNAME}" \ | |
| --form "endpointId=${PORTAINER_ENDPOINTID}" \ | |
| --form "Env=${STACKENV}" \ | |
| --form "file=@compose.yaml" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment