{"id":13410514,"url":"https://github.com/greenled/portainer-stack-utils","last_synced_at":"2025-10-27T16:31:47.275Z","repository":{"id":57491921,"uuid":"158273186","full_name":"greenled/portainer-stack-utils","owner":"greenled","description":"CLI client for Portainer","archived":false,"fork":false,"pushed_at":"2020-05-04T22:50:31.000Z","size":473,"stargazers_count":75,"open_issues_count":13,"forks_count":16,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-09-28T21:05:20.312Z","etag":null,"topics":["api-client","bash","continuous-deployment","deployment","docker","docker-compose","go","httpie","jq","json-configuration","proxy","yaml-configuration"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/greenled/portainer-stack-utils/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greenled.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-19T18:39:06.000Z","updated_at":"2024-09-22T06:35:04.000Z","dependencies_parsed_at":"2022-08-28T11:24:31.204Z","dependency_job_id":null,"html_url":"https://github.com/greenled/portainer-stack-utils","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greenled%2Fportainer-stack-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greenled%2Fportainer-stack-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greenled%2Fportainer-stack-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greenled%2Fportainer-stack-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greenled","download_url":"https://codeload.github.com/greenled/portainer-stack-utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219860932,"owners_count":16556009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","bash","continuous-deployment","deployment","docker","docker-compose","go","httpie","jq","json-configuration","proxy","yaml-configuration"],"created_at":"2024-07-30T20:01:07.429Z","updated_at":"2025-10-27T16:31:46.974Z","avatar_url":"https://github.com/greenled.png","language":"Go","funding_links":[],"categories":["Development with Docker","Docker","Developer Workflow"],"sub_categories":["API Client","Telegram"],"readme":"# Portainer Stack Utils\n\n[![CircleCI](https://circleci.com/gh/greenled/portainer-stack-utils.svg?style=svg)](https://circleci.com/gh/greenled/portainer-stack-utils)\n[![Docker Automated build](https://img.shields.io/docker/automated/greenled/portainer-stack-utils.svg)](https://hub.docker.com/r/greenled/portainer-stack-utils/)\n[![Docker Pulls](https://img.shields.io/docker/pulls/greenled/portainer-stack-utils.svg)](https://hub.docker.com/r/greenled/portainer-stack-utils/)\n[![Microbadger](https://images.microbadger.com/badges/image/greenled/portainer-stack-utils.svg)](http://microbadger.com/images/greenled/portainer-stack-utils \"Image size\")\n[![Go Report Card](https://goreportcard.com/badge/github.com/greenled/portainer-stack-utils)](https://goreportcard.com/report/github.com/greenled/portainer-stack-utils)\n\n## Table of contents\n\n- [Overview](#overview)\n  - [Mission](#mission)\n  - [Vision](#vision)\n- [Supported Portainer API](#supported-portainer-api)\n- [How to install](#how-to-install)\n- [How to use](#how-to-use)\n  - [Configuration](#configuration)\n    - [Inline flags](#inline-flags)\n    - [Environment variables](#environment-variables)\n    - [Configuration files](#configuration-files)\n      - [YAML configuration file](#yaml-configuration-file)\n      - [JSON configuration file](#json-configuration-file)\n  - [Environment variables for deployed stacks](#environment-variables-for-deployed-stacks)\n  - [Endpoint's Docker API proxy](#endpoints-docker-api-proxy)\n    - [Known limitations](#known-limitations)\n  - [Log level](#log-level)\n  - [Exit statuses](#exit-statuses)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Overview\n\nPortainer Stack Utils is a CLI client for [Portainer](https://portainer.io/) written in Go.\n\n**Attention:** The `master` branch contains the next major version, still unstable and under heavy development. A more stable (and also older) version is available as a Bash script in [release 0.1.1](https://github.com/greenled/portainer-stack-utils/releases/0.1.1), and also as a [Docker image](https://hub.docker.com/r/greenled/portainer-stack-utils). There is ongoing work in `1-0-next` branch to enhace that Bash version.\n\n### Mission\n\nTo provide an **easy** and **extensible** way of interacting with Portainer in automated, non-interactive environments.\n\n### Vision\n\nBy December 2019 Portainer Stack Utils:\n\n- [ ] Has a stable API\n- [ ] Doubles its [GitHub stargazers](https://github.com/greenled/portainer-stack-utils/stargazes) (+50)\n- [ ] Triples its [DockerHub downloads](https://hub.docker.com/r/greenled/portainer-stack-utils) (+900)\n\n## Supported Portainer API\n\nThis application was created for the latest Portainer API, which at the time of writing is [1.22.0](https://app.swaggerhub.com/apis/deviantony/Portainer/1.22.0).\n\n## How to install\n\nDownload the binaries for your platform and architecture from [the releases page](https://github.com/greenled/portainer-stack-utils/releases).\n\n## How to use\n\nThe application is built on a structure of commands, arguments and flags.\n                   \n**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions:\n\n```text\nAPPNAME COMMAND ARG --FLAG\n```\n\nHere are some examples:\n\n```bash\npsu help\npsu status --help\npsu stack ls --endpoint primary --format \"{{ .Name }}\"\npsu stack deploy mystack --stack-file docker-compose.yml -e .env --log-level debug\npsu stack rm mystack\n```\n\nCommands can have subcommands, like `stack ls` and `stack deploy` in the previous example. They can also have aliases (i.e. `create` and `up` are aliases of `deploy`).\n\nSome flags are global, which means they affect every command (i.e. `--log-level`), while others are local, which mean they only affect the command they belong to (i.e. `--stack-file` flag from `deploy` command). Also, some flags have a short version (i.e `--insecure`, `-i`).\n\n### Configuration\n\nThe program can be configured through [inline flags](#inline-flags) (i.e. `--user`), [environment variables](#environment-variables) (i.e. `PSU_USER=admin`) and/or [configuration files](#configuration-files), which translate into multi-level configuration keys in the form `x[.y[.z[...]]]`. Run `psu config ls` to see all available configuration options.\n\nAll three methods can be combined. If a configuration key is set in several places the order of precedence is:\n\n1. Inline flags\n2. Environment variables\n3. Configuration file\n4. Default values\n\n#### Inline flags\n\nConfiguration can be set through inline flags. Valid combinations of commands and flags directly map to configuration keys:\n\n| Configuration key | Command | Flag |\n| :---------------- | :------ | :--- |\n| user | psu | --user |\n| stack.list.format | psu stack list | --format |\n| stack.deploy.env-file | stack deploy | --env-file |\n\nRun `psu help COMMAND` to see all available flags for a given command.\n\n#### Environment variables\n\nConfiguration can be set through environment variables. Supported environment variables follow the `PSU_[COMMAND_[SUBCOMMAND_]]FLAG` naming pattern:\n\n| Configuration key | Environment variable |\n| :---------------- | :------------------- |\n| user | PSU_USER |\n| stack.list.format | PSU_STACK_LIST_FORMAT |\n| stack.deploy.env-file | PSU_STACK_DEPLOY_ENV_FILE |\n\n*Note that all supported environment variables are prefixed with \"PSU_\" to avoid name clashing. Characters \"-\" and \".\" in configuration key names are replaced with \"_\" in environment variable names.*\n\n#### Configuration files\n\nConfiguration can be set through a configuration file. Supported file formats are [JSON](#json-configuration-file), TOML, [YAML](#yaml-configuration-file), HCL, envfile and Java properties config files. Use the `--config` global flag to specify a configuration file. File `$HOME/.psu.yaml` is used by default if present.\n\n##### YAML configuration file\n\nA Yaml configuration file should look like this:\n\n```yaml\nlog-level: debug\nuser: admin\ninsecure: true\nstack.list.format: table\nstack:\n  deploy.env-file: .env\n  deploy:\n    stack-file: docker-compose.yml\n```\n\n*Note that flat and nested keys are both valid.*\n\n##### JSON configuration file\n\nA JSON configuration file should look like this:\n\n```json\n{\n  \"log-level\": \"debug\",\n  \"user\": \"admin\",\n  \"insecure\": true,\n  \"stack.list.format\": \"table\",\n  \"stack\": {\n    \"deploy.env-file\": \".env\",\n    \"deploy\": {\n      \"stack-file\": \"docker-compose.yml\"\n    }\n  }\n}\n```\n\n*Note that flat and nested keys are both valid.*\n\n### Environment variables for deployed stacks\n\nYou will often want to set environment variables in your deployed stacks. You can do so through the `stack.deploy.env-file` [configuration key](#configuration). :\n\n```bash\ntouch .env\necho \"MYSQL_ROOT_PASSWORD=agoodpassword\" \u003e\u003e .env\necho \"ALLOWED_HOSTS=*\" \u003e\u003e .env\n\n# Using --env-file flag\npsu stack deploy django-stack -c /path/to/docker-compose.yml -e .env\n\n# Using PSU_STACK_DEPLOY_ENV_FILE environment variable\nPSU_STACK_DEPLOY_ENV_FILE=.env\npsu stack deploy django-stack -c /path/to/docker-compose.yml\n\n# Using a config file\necho \"stack.deploy.env-file: .env\" \u003e .config.yml\npsu stack deploy django-stack -c /path/to/docker-compose.yml --config .config.yml\n```\n\n### Endpoint's Docker API proxy\n\nIf you want finer-grained control over an endpoint's Docker daemon you can expose it through a proxy and configure a local Docker client to use it.\n\nFirst, expose the endpoint's Docker API:\n\n```bash\npsu proxy --endpoint primary --address 127.0.0.1:2375\n```\n\nThen (in a different shell), configure a local Docker client to use the exposed API:\n\n```bash\nexport DOCKER_HOST=tcp://127.0.0.1:2375\n```\n\nNow you can run `docker ...` commands in the `primary` endpoint as in a local Docker installation, **with the added benefit of using Portainer's RBAC**.\n\n*Note that creating stacks through `docker stack ...` instead of `psu stack ...` will give you *limited* control over them, as they are created outside of Portainer.*\n\n#### Known limitations\n\n- Docker commands requiring a websocket connection (like `docker attach`, `docker exec`, `docker system events`) are known to fail with an `unable to upgrade to tcp, received 200` error or just hang up (see #31).\n\n### Log level\n\nYou can control how much noise you want the program to do by setting the log level. There are seven log levels:\n\n- *panic*: Unexpected errors that stop program execution.\n- *fatal*: Expected errors that stop program execution.\n- *error*: Errors that should definitely be noted but don't stop the program execution.\n- *warning*: Non-critical events that deserve eyes.\n- *info*: General events about what's going on inside the program. This is the default level.\n- *debug*: Very verbose logging. Usually only enabled when debugging.\n- *trace*: Finer-grained logging than the *debug* level.\n\n**WARNING**: **trace** level will print sensitive information, like Portainer API requests and responses (with authentication tokens, stacks environment variables, and so on). Avoid using **trace** level in CI/CD environments, as those logs are usually recorded.\n\nThis is an example with *debug* level:\n\n```bash\npsu stack deploy asd --endpoint primary --log-level debug\n```\n\nThe output would look like:\n\n```text\nDEBU[0000] Getting endpoint's Docker info     endpoint=primary\nDEBU[0000] Getting stack                      endpoint=primary stack=asd\nDEBU[0000] Stack not found                    stack=asd\nINFO[0000] Creating stack                     endpoint=primary stack=asd\nINFO[0000] Stack created                      endpoint=primary id=89 stack=asd\n```\n\n### Exit statuses\n\n- *0*: Program executed normally.\n- *1*: An expected error stopped program execution.\n- *2*: An unexpected error stopped program execution.\n\n## Contributing\n\nContributing guidelines can be found in [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nSource code contained by this project is licensed under the [GNU General Public License version 3](https://www.gnu.org/licenses/gpl-3.0.en.html). See [LICENSE](LICENSE) file for reference.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreenled%2Fportainer-stack-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreenled%2Fportainer-stack-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreenled%2Fportainer-stack-utils/lists"}