├── .gitignore ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── Dockerfile ├── README.md ├── docs ├── architecture.md ├── assets │ ├── images │ │ ├── DD deployed.png │ │ ├── DD first page.png │ │ ├── DD marketplace.png │ │ ├── DD- deploying.png │ │ ├── DD-Previews.png │ │ ├── DDcomposespec.png │ │ ├── DDlogs.png │ │ ├── account-dropdown.webp │ │ ├── account-settings-registries.png │ │ ├── accounts-do-not-match-error.webp │ │ ├── acr-login.png │ │ ├── add-compose-in-settings.webp │ │ ├── add-compose.png │ │ ├── add-container-registry-credentials.png │ │ ├── add-database-secrets.png │ │ ├── add-secret.webp │ │ ├── add-secrets.png │ │ ├── agile-with-cp.svg │ │ ├── architecture.png │ │ ├── authorize-uffizzi-cloud.png │ │ ├── authorize-uffizzi.webp │ │ ├── bad-credentials.webp │ │ ├── blog-1-link-compose.png │ │ ├── blog-1-new-compose.png │ │ ├── blog-1-new-preview.png │ │ ├── build-logs-menu.jpg │ │ ├── choose-org.webp │ │ ├── compose-added.webp │ │ ├── compose-four.png │ │ ├── compose-in-git.png │ │ ├── compose-one.png │ │ ├── compose-saved.webp │ │ ├── compose-target-branch.webp │ │ ├── compose-three.png │ │ ├── compose-two.png │ │ ├── compose-validation-error-secret-not-found.png │ │ ├── configure-github-app.png │ │ ├── configure-github.webp │ │ ├── configure-repositories.png │ │ ├── container-logs.webp │ │ ├── create-pr.webp │ │ ├── create-team.webp │ │ ├── delete-secret.png │ │ ├── delete.png │ │ ├── deploying-preview.webp │ │ ├── docker-hub-access-token.png │ │ ├── docker-hub-delete-access-token-confirmation.png │ │ ├── docker-hub-delete-access-token.png │ │ ├── docker-hub-generate-access-token.png │ │ ├── docker-hub-login.png │ │ ├── ecr-login.png │ │ ├── ecr-webhook-screenshot.png │ │ ├── enable-password-protection.png │ │ ├── environment-url.png │ │ ├── event-logs.png │ │ ├── favicon.png │ │ ├── gcr-login.png │ │ ├── gha-bot.png │ │ ├── gha-jobs.jpg │ │ ├── ghcr-delete-pat.png │ │ ├── ghcr-login.png │ │ ├── ghcr.png │ │ ├── github-actions-secrets.webp │ │ ├── github-add-secret.png │ │ ├── github-apps-configure.png │ │ ├── github-environments-2.png │ │ ├── github-environments-2.webp │ │ ├── github-environments-3.webp │ │ ├── github-environments-4.webp │ │ ├── github-environments-5.webp │ │ ├── github-environments.webp │ │ ├── github-install-uffizzi-cloud.png │ │ ├── github-repository-secrets.png │ │ ├── http-dialog.webp │ │ ├── initiated-preview.png │ │ ├── install-and-authorize-uffizzi-cloud.png │ │ ├── install-github-app.webp │ │ ├── invalid-compose-erorr.webp │ │ ├── link-to-compose-file.png │ │ ├── linked-compose-file.png │ │ ├── logs.png │ │ ├── microservices-architecture-with-nginx.webp │ │ ├── new-uffizzi-ci-project.webp │ │ ├── open-pr.png │ │ ├── password-protection.webp │ │ ├── pr-comment.webp │ │ ├── preview-link-live.png │ │ ├── preview-status.png │ │ ├── project-list.png │ │ ├── project-settings-slug.png │ │ ├── project-slug.png │ │ ├── quickstart-gitlab-build-pipelines.png │ │ ├── quickstart-gitlab-create-mr.png │ │ ├── quickstart-gitlab-fork-1.png │ │ ├── quickstart-gitlab-fork-2.png │ │ ├── repository-access.png │ │ ├── resolve-compose-errors.webp │ │ ├── safari-preferences-privacy.webp │ │ ├── safari-preferences.webp │ │ ├── save-and-validate-compose.webp │ │ ├── secret-name-value.png │ │ ├── secrets.png │ │ ├── select-repositories.webp │ │ ├── set-up-project.webp │ │ ├── settings-compose-file.png │ │ ├── settings-compose-resolve-errors.png │ │ ├── settings-compose-synced.png │ │ ├── settings-integrations-container-registries.png │ │ ├── settings-integrations-github.png │ │ ├── settings-integrations.png │ │ ├── settings-secrets.png │ │ ├── sign-in-to-ecr.png │ │ ├── template-environment-variables.png │ │ ├── template-envvars-textbox.png │ │ ├── u-logo.svg │ │ ├── uffizzi-ci-comment.png │ │ ├── uffizzi-ci-comment.webp │ │ └── voting-app-architecture.webp │ └── scripts │ │ ├── uffizzi_ecr_webhook_configure.bash │ │ └── uffizzi_ecr_webhook_remove.bash ├── docker-compose-environment.md ├── guides │ ├── configure-credentials.md │ ├── container-registry-integrations.md │ ├── demo-on-uffizzi.md │ ├── docker-compose-template.md │ ├── environment-variables.md │ ├── expose-multiple-routes.md │ ├── github-environment.md │ ├── integrate-with-ci.md │ ├── logs.md │ ├── password-protected.md │ ├── secrets.md │ ├── set-up-your-account.md │ ├── single-sign-on.md │ └── support-microservices-in-ephemeral-environments-with-nginx.md ├── index.md ├── install.md ├── quickstart-uffizzi-ci.md ├── quickstart.md ├── references │ ├── cli.md │ ├── compose-spec.md │ ├── example-compose.md │ ├── uffizzi-ci.md │ └── uffizzi-environment-variables.md ├── stylesheets │ └── extra.css ├── topics │ ├── ci-cd-registry.md │ ├── continuous-previews.md │ ├── docker-extension-partner.md │ ├── networking.md │ ├── oidc.md │ ├── rbac.md │ ├── single-page-applications.md │ ├── teams-and-accounts.md │ ├── virtual-clusters.md │ └── why-uffizzi.md ├── troubleshooting │ ├── debugging.md │ ├── file-or-directory-is-too-large.md │ └── most-common-problems.md ├── using-uffizzi.md └── virtual-cluster-environment.md ├── mkdocs.yml ├── nginx └── default.conf ├── requirements.txt └── uffizzi-compose.yml /.gitignore: -------------------------------------------------------------------------------- 1 | site/ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to Uffizzi Project Documentation 2 | 3 | First, thank you for considering contributing to Uffizzi! You are what drive the open source community. 4 | 5 | Uffizzi welcomes all contributions from everyone, not just Pull Requests. You can also help by filing detailed bug reports, proposing new documentation, and sharing Continuous Previews and Uffizzi with your local community. 6 | 7 | **Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://kcd.im/pull-request) 8 | 9 | If you find a security vulnerability, DO NOT open an issue. Email instead. 10 | 11 | ## Community 12 | 13 | Please join us on the [Uffizzi Slack](https://join.slack.com/t/uffizzi/shared_invite/zt-ffr4o3x0-J~0yVT6qgFV~wmGm19Ux9A) where we look forward to discussing any feature requests, bugs, and other proposed changes. 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-alpine AS build 2 | 3 | # Install requirements. 4 | COPY ./requirements.txt / 5 | RUN pip install --requirement /requirements.txt 6 | 7 | # Copy source. 8 | COPY ./mkdocs.yml / 9 | COPY ./docs /docs 10 | 11 | # Build static files. 12 | RUN mkdocs build 13 | 14 | # Second stage 15 | FROM nginx:1-alpine 16 | 17 | # Replace nginx' default configuration with ours. 18 | COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf 19 | 20 | # Copy built static files to HTTP root. 21 | COPY --from=build /site /usr/share/nginx/html/ 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Uffizzi Docs 2 | 3 | Documentation for the Uffizzi Full-Stack Previews Engine 4 | 5 | This documentation covers general concepts and technical details for: 6 | 7 | * [Uffizzi App](https://github.com/UffizziCloud/uffizzi_app) - The primary REST API for creating and managing Previews 8 | * [Uffizzi Controller](https://github.com/UffizziCloud/uffizzi_controller) - A smart proxy service that handles requests from Uffizzi App to the Kubernetes API 9 | * [Uffizzi CLI](https://github.com/UffizziCloud/uffizzi_cli) - A command-line interface for Uffizzi App 10 | * [Uffizzi Dashboard](https://uffizzi.com) - A graphical user interface for Uffizzi App 11 | 12 | These docs are hosted at https://docs.uffizzi.com 13 | -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 | # Uffizzi Platform Architecture 2 | 3 | ![Uffizzi Platform Architecture](assets/images/architecture.png) -------------------------------------------------------------------------------- /docs/assets/images/DD deployed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DD deployed.png -------------------------------------------------------------------------------- /docs/assets/images/DD first page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DD first page.png -------------------------------------------------------------------------------- /docs/assets/images/DD marketplace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DD marketplace.png -------------------------------------------------------------------------------- /docs/assets/images/DD- deploying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DD- deploying.png -------------------------------------------------------------------------------- /docs/assets/images/DD-Previews.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DD-Previews.png -------------------------------------------------------------------------------- /docs/assets/images/DDcomposespec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DDcomposespec.png -------------------------------------------------------------------------------- /docs/assets/images/DDlogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/DDlogs.png -------------------------------------------------------------------------------- /docs/assets/images/account-dropdown.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/account-dropdown.webp -------------------------------------------------------------------------------- /docs/assets/images/account-settings-registries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/account-settings-registries.png -------------------------------------------------------------------------------- /docs/assets/images/accounts-do-not-match-error.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/accounts-do-not-match-error.webp -------------------------------------------------------------------------------- /docs/assets/images/acr-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/acr-login.png -------------------------------------------------------------------------------- /docs/assets/images/add-compose-in-settings.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/add-compose-in-settings.webp -------------------------------------------------------------------------------- /docs/assets/images/add-compose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/add-compose.png -------------------------------------------------------------------------------- /docs/assets/images/add-container-registry-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/add-container-registry-credentials.png -------------------------------------------------------------------------------- /docs/assets/images/add-database-secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/add-database-secrets.png -------------------------------------------------------------------------------- /docs/assets/images/add-secret.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/add-secret.webp -------------------------------------------------------------------------------- /docs/assets/images/add-secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/add-secrets.png -------------------------------------------------------------------------------- /docs/assets/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/architecture.png -------------------------------------------------------------------------------- /docs/assets/images/authorize-uffizzi-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/authorize-uffizzi-cloud.png -------------------------------------------------------------------------------- /docs/assets/images/authorize-uffizzi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/authorize-uffizzi.webp -------------------------------------------------------------------------------- /docs/assets/images/bad-credentials.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/bad-credentials.webp -------------------------------------------------------------------------------- /docs/assets/images/blog-1-link-compose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/blog-1-link-compose.png -------------------------------------------------------------------------------- /docs/assets/images/blog-1-new-compose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/blog-1-new-compose.png -------------------------------------------------------------------------------- /docs/assets/images/blog-1-new-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/blog-1-new-preview.png -------------------------------------------------------------------------------- /docs/assets/images/build-logs-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/build-logs-menu.jpg -------------------------------------------------------------------------------- /docs/assets/images/choose-org.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/choose-org.webp -------------------------------------------------------------------------------- /docs/assets/images/compose-added.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-added.webp -------------------------------------------------------------------------------- /docs/assets/images/compose-four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-four.png -------------------------------------------------------------------------------- /docs/assets/images/compose-in-git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-in-git.png -------------------------------------------------------------------------------- /docs/assets/images/compose-one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-one.png -------------------------------------------------------------------------------- /docs/assets/images/compose-saved.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-saved.webp -------------------------------------------------------------------------------- /docs/assets/images/compose-target-branch.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-target-branch.webp -------------------------------------------------------------------------------- /docs/assets/images/compose-three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-three.png -------------------------------------------------------------------------------- /docs/assets/images/compose-two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-two.png -------------------------------------------------------------------------------- /docs/assets/images/compose-validation-error-secret-not-found.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/compose-validation-error-secret-not-found.png -------------------------------------------------------------------------------- /docs/assets/images/configure-github-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/configure-github-app.png -------------------------------------------------------------------------------- /docs/assets/images/configure-github.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/configure-github.webp -------------------------------------------------------------------------------- /docs/assets/images/configure-repositories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/configure-repositories.png -------------------------------------------------------------------------------- /docs/assets/images/container-logs.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/container-logs.webp -------------------------------------------------------------------------------- /docs/assets/images/create-pr.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/create-pr.webp -------------------------------------------------------------------------------- /docs/assets/images/create-team.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/create-team.webp -------------------------------------------------------------------------------- /docs/assets/images/delete-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/delete-secret.png -------------------------------------------------------------------------------- /docs/assets/images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/delete.png -------------------------------------------------------------------------------- /docs/assets/images/deploying-preview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/deploying-preview.webp -------------------------------------------------------------------------------- /docs/assets/images/docker-hub-access-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/docker-hub-access-token.png -------------------------------------------------------------------------------- /docs/assets/images/docker-hub-delete-access-token-confirmation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/docker-hub-delete-access-token-confirmation.png -------------------------------------------------------------------------------- /docs/assets/images/docker-hub-delete-access-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/docker-hub-delete-access-token.png -------------------------------------------------------------------------------- /docs/assets/images/docker-hub-generate-access-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/docker-hub-generate-access-token.png -------------------------------------------------------------------------------- /docs/assets/images/docker-hub-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/docker-hub-login.png -------------------------------------------------------------------------------- /docs/assets/images/ecr-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/ecr-login.png -------------------------------------------------------------------------------- /docs/assets/images/ecr-webhook-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/ecr-webhook-screenshot.png -------------------------------------------------------------------------------- /docs/assets/images/enable-password-protection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/enable-password-protection.png -------------------------------------------------------------------------------- /docs/assets/images/environment-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/environment-url.png -------------------------------------------------------------------------------- /docs/assets/images/event-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/event-logs.png -------------------------------------------------------------------------------- /docs/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/favicon.png -------------------------------------------------------------------------------- /docs/assets/images/gcr-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/gcr-login.png -------------------------------------------------------------------------------- /docs/assets/images/gha-bot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/gha-bot.png -------------------------------------------------------------------------------- /docs/assets/images/gha-jobs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/gha-jobs.jpg -------------------------------------------------------------------------------- /docs/assets/images/ghcr-delete-pat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/ghcr-delete-pat.png -------------------------------------------------------------------------------- /docs/assets/images/ghcr-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/ghcr-login.png -------------------------------------------------------------------------------- /docs/assets/images/ghcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/ghcr.png -------------------------------------------------------------------------------- /docs/assets/images/github-actions-secrets.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-actions-secrets.webp -------------------------------------------------------------------------------- /docs/assets/images/github-add-secret.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-add-secret.png -------------------------------------------------------------------------------- /docs/assets/images/github-apps-configure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-apps-configure.png -------------------------------------------------------------------------------- /docs/assets/images/github-environments-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-environments-2.png -------------------------------------------------------------------------------- /docs/assets/images/github-environments-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-environments-2.webp -------------------------------------------------------------------------------- /docs/assets/images/github-environments-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-environments-3.webp -------------------------------------------------------------------------------- /docs/assets/images/github-environments-4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-environments-4.webp -------------------------------------------------------------------------------- /docs/assets/images/github-environments-5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-environments-5.webp -------------------------------------------------------------------------------- /docs/assets/images/github-environments.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-environments.webp -------------------------------------------------------------------------------- /docs/assets/images/github-install-uffizzi-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-install-uffizzi-cloud.png -------------------------------------------------------------------------------- /docs/assets/images/github-repository-secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/github-repository-secrets.png -------------------------------------------------------------------------------- /docs/assets/images/http-dialog.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/http-dialog.webp -------------------------------------------------------------------------------- /docs/assets/images/initiated-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/initiated-preview.png -------------------------------------------------------------------------------- /docs/assets/images/install-and-authorize-uffizzi-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/install-and-authorize-uffizzi-cloud.png -------------------------------------------------------------------------------- /docs/assets/images/install-github-app.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/install-github-app.webp -------------------------------------------------------------------------------- /docs/assets/images/invalid-compose-erorr.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/invalid-compose-erorr.webp -------------------------------------------------------------------------------- /docs/assets/images/link-to-compose-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/link-to-compose-file.png -------------------------------------------------------------------------------- /docs/assets/images/linked-compose-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/linked-compose-file.png -------------------------------------------------------------------------------- /docs/assets/images/logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/logs.png -------------------------------------------------------------------------------- /docs/assets/images/microservices-architecture-with-nginx.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/microservices-architecture-with-nginx.webp -------------------------------------------------------------------------------- /docs/assets/images/new-uffizzi-ci-project.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/new-uffizzi-ci-project.webp -------------------------------------------------------------------------------- /docs/assets/images/open-pr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/open-pr.png -------------------------------------------------------------------------------- /docs/assets/images/password-protection.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/password-protection.webp -------------------------------------------------------------------------------- /docs/assets/images/pr-comment.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/pr-comment.webp -------------------------------------------------------------------------------- /docs/assets/images/preview-link-live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/preview-link-live.png -------------------------------------------------------------------------------- /docs/assets/images/preview-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/preview-status.png -------------------------------------------------------------------------------- /docs/assets/images/project-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/project-list.png -------------------------------------------------------------------------------- /docs/assets/images/project-settings-slug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/project-settings-slug.png -------------------------------------------------------------------------------- /docs/assets/images/project-slug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/project-slug.png -------------------------------------------------------------------------------- /docs/assets/images/quickstart-gitlab-build-pipelines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/quickstart-gitlab-build-pipelines.png -------------------------------------------------------------------------------- /docs/assets/images/quickstart-gitlab-create-mr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/quickstart-gitlab-create-mr.png -------------------------------------------------------------------------------- /docs/assets/images/quickstart-gitlab-fork-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/quickstart-gitlab-fork-1.png -------------------------------------------------------------------------------- /docs/assets/images/quickstart-gitlab-fork-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/quickstart-gitlab-fork-2.png -------------------------------------------------------------------------------- /docs/assets/images/repository-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/repository-access.png -------------------------------------------------------------------------------- /docs/assets/images/resolve-compose-errors.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/resolve-compose-errors.webp -------------------------------------------------------------------------------- /docs/assets/images/safari-preferences-privacy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/safari-preferences-privacy.webp -------------------------------------------------------------------------------- /docs/assets/images/safari-preferences.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/safari-preferences.webp -------------------------------------------------------------------------------- /docs/assets/images/save-and-validate-compose.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/save-and-validate-compose.webp -------------------------------------------------------------------------------- /docs/assets/images/secret-name-value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/secret-name-value.png -------------------------------------------------------------------------------- /docs/assets/images/secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/secrets.png -------------------------------------------------------------------------------- /docs/assets/images/select-repositories.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/select-repositories.webp -------------------------------------------------------------------------------- /docs/assets/images/set-up-project.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/set-up-project.webp -------------------------------------------------------------------------------- /docs/assets/images/settings-compose-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-compose-file.png -------------------------------------------------------------------------------- /docs/assets/images/settings-compose-resolve-errors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-compose-resolve-errors.png -------------------------------------------------------------------------------- /docs/assets/images/settings-compose-synced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-compose-synced.png -------------------------------------------------------------------------------- /docs/assets/images/settings-integrations-container-registries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-integrations-container-registries.png -------------------------------------------------------------------------------- /docs/assets/images/settings-integrations-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-integrations-github.png -------------------------------------------------------------------------------- /docs/assets/images/settings-integrations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-integrations.png -------------------------------------------------------------------------------- /docs/assets/images/settings-secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/settings-secrets.png -------------------------------------------------------------------------------- /docs/assets/images/sign-in-to-ecr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/sign-in-to-ecr.png -------------------------------------------------------------------------------- /docs/assets/images/template-environment-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/template-environment-variables.png -------------------------------------------------------------------------------- /docs/assets/images/template-envvars-textbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/template-envvars-textbox.png -------------------------------------------------------------------------------- /docs/assets/images/u-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/images/uffizzi-ci-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/uffizzi-ci-comment.png -------------------------------------------------------------------------------- /docs/assets/images/uffizzi-ci-comment.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/uffizzi-ci-comment.webp -------------------------------------------------------------------------------- /docs/assets/images/voting-app-architecture.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UffizziCloud/docs/446c7f70ad63de658f0e03af75b107910759ef3f/docs/assets/images/voting-app-architecture.webp -------------------------------------------------------------------------------- /docs/assets/scripts/uffizzi_ecr_webhook_configure.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export NAME="uffizzi-webhook-ecr-image-push" 4 | 5 | aws events create-connection --name $NAME --authorization-type API_KEY --auth-parameters '{ "ApiKeyAuthParameters": { "ApiKeyName": "AWS_PRIVATE_KEY", "ApiKeyValue": "test" } }' 6 | 7 | export CONNECTION_ARN=`aws events describe-connection --name $NAME --query ConnectionArn --output text` 8 | 9 | aws events create-api-destination --name $NAME --connection-arn $CONNECTION_ARN --invocation-endpoint https://app.uffizzi.com/api/v1/webhooks/amazon --http-method POST 10 | 11 | export API_DESTINATION_ARN=`aws events describe-api-destination --name $NAME --query ApiDestinationArn --output text` 12 | 13 | aws events put-rule --name $NAME --state ENABLED --event-pattern '{ "source": ["aws.ecr"], "detail-type": ["ECR Image Action"], "detail": { "action-type": ["PUSH"], "result": ["SUCCESS"] } }' 14 | 15 | aws iam create-role --role-name $NAME --path '/service-role/' --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sts:AssumeRole" }] }' 16 | 17 | export ROLE_ARN=`aws iam get-role --role-name $NAME --query 'Role.Arn' --output text` 18 | 19 | aws iam put-role-policy --role-name $NAME --policy-name $NAME --policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "events:*", "Resource": "*" }] }' 20 | 21 | aws events put-targets --rule $NAME --targets "[{ \"Id\": \"$NAME\", \"Arn\": \"$API_DESTINATION_ARN\", \"RoleArn\": \"$ROLE_ARN\", \"HttpParameters\": { \"PathParameterValues\": [], \"HeaderParameters\": {}, \"QueryStringParameters\": {} } }]" 22 | -------------------------------------------------------------------------------- /docs/assets/scripts/uffizzi_ecr_webhook_remove.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export NAME="uffizzi-webhook-ecr-image-push" 4 | 5 | aws events remove-targets --rule $NAME --ids $NAME 6 | 7 | aws iam delete-role-policy --role-name $NAME --policy-name $NAME 8 | 9 | aws iam delete-role --role-name $NAME 10 | 11 | aws events delete-rule --name $NAME 12 | 13 | aws events delete-api-destination --name $NAME 14 | 15 | aws events delete-connection --name $NAME 16 | -------------------------------------------------------------------------------- /docs/guides/configure-credentials.md: -------------------------------------------------------------------------------- 1 | **Section 3 of 3** 2 | # Configure credentials 3 | 4 | In this section, we'll create a Uffizzi Cloud account and connect it with your CI provider. 5 | 6 | ## **Uffizzi CI** 7 | 8 | If you're using Uffizzi CI, you will need to link to the Docker Compose template in your GitHub repository from the Uffizzi Dashboard. If you haven't already done so, sign up at [Uffizzi Cloud](https://app.uffizzi.com/sign_up), and then follow the steps to set up your account. 9 | 10 |
1. Connect the Uffizzi GitHub App 11 |

In this step you will install the Uffizzi GitHub App and grant Uffizzi access to the repositories you want to deploy. Login to Uffizzi, then navigate to Account > Settings > General, then select Configure next to the GitHub option. 12 |

13 | 14 |
15 |

You'll be asked to Install Uffizzi Cloud, then grant access to your repositories.

16 |
17 | 18 |
19 |

Similarly, you can manage the Uffizzi app installation from GitHub by navigating to Settings > Applications > Uffizzi Cloud > Configure

20 | 21 |
22 |
23 | 24 | If the Docker Compose template you created in Section 1 references images stored in a private container registry, add those credentials in this step, as indicated in the screenshot below: 25 | 26 |
2. Add application secrets 27 |

If your compose file includes [application secrets](https://docs.uffizzi.com/references/compose-spec/#secrets), such as database credentials, you can add them in the Uffizzi Dashboard. Navigate to your project, then select Specs > Secrets > NEW SECRET. This will open a modal, where you can input your secrets as NAME=VALUE pairs. Be sure to add one secret per line, separatedy by = with no white spaces. 28 |

29 | 30 |
31 | 32 |
33 |

Once the secrets are saved, you will not be able to view or edit their values. To make changes to a secret, first delete the old secret, then create a new one. 34 |

35 | 36 |
3. Link to your Docker Compose template 37 |

In this final step, we'll link to our Docker Compose template that's stored in our GitHub repository. To do this, navigate to your project, then select Specs > Compose > NEW COMPOSE. Next, select the repository, branch (typically this is the branch you open pull requests against), and name of the compose file. Finally, select VALIDATE & SAVE. 38 |

39 | 40 |
41 |

Note, if you did not add your secrets as described in the previous step, you will see a validation error with a link to add your secretes.

42 | 43 |
44 |

Once your compose file has been successfully added, you will see it in the Uffizzi Dashboard with a link to its source on GitHub. Any changes you make to this compose file on GitHub will be synced in the Uffizzi Dashboard.

45 | 46 |
47 |
48 | 49 | That's it! Uffizzi is now configured with your Docker Compose template. To test your setup, you can manually deploy your primary branch to an on-demand test environment using the **Test Compose** button in the Uffizzi Dashboard, or try opening a pull request on GitHub to deploy a feature branch. 50 | 51 | ## **Connect container registy credentials to Uffizzi** 52 | 53 | Follow this section if you're using an external container registry, such as GHCR, ECR, or Docker Hub, to store your built images (i.e. You are not relying on Uffizz CI to storage images for you). 54 | 55 | How you add container registry credentials to Uffizzi depends on your registry of choice. 56 | 57 | ### GitHub Container Registry (ghcr.io) 58 | 59 |

If you use GitHub Container Registry (ghcr.io), you will need to generate a GitHub personal access token with access to the read:packages scope. Once this token is generated, add it as a GitHub repository secret, then pass this value to the reusable workflow using the personal-access-token parameter, as described in the previous section.

60 | 61 | ``` yaml 62 | secrets: 63 | personal-access-token: ${{ secrets.GHCR_ACCESS_TOKEN }} 64 | ``` 65 | 66 | Once you've created a personal access token, you should add it in your Uffizzi Account Settings. 67 | 68 |
Add GHCR personal access token in Account Settings 69 | Login to Uffizzi, then navigate to Account > Settings > Registries, then select Configure next to the GHCR option.

70 | 71 |
72 | 73 |
74 |

Enter your GitHub username and personal access token, then select Sign in to GitHub Container Registry. 75 |

76 | 77 | ### ECR, ACR, GCR, Docker Hub 78 | If you use Amazon ECR, Azure Container Registry (ACR), Google Container Registry (GCR), or Docker Hub, you should add your credentials as [GitHub repository secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository). 79 | 80 |
See this AWS ECR example 81 |

If you use Amazon ECR, Azure Container Registry (ACR), Google Container Registry (GCR), or Docker Hub, you should add your credentials as GitHub repository secrets. In the highlighted example below, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are used:

82 | 83 | ``` yaml title=".github/workflows/ci.yml" hl_lines="15 16" 84 | [...] 85 | 86 | jobs: 87 | # Build and push app image 88 | build-app: 89 | name: Build and Push `app` 90 | runs-on: ubuntu-latest 91 | outputs: 92 | tags: ${{ steps.meta.outputs.tags }} 93 | steps: 94 | - name: Login to ECR 95 | uses: docker/login-action@v2 96 | with: 97 | registry: 263049488290.dkr.ecr.us-east-1.amazonaws.com 98 | username: ${{ secrets.AWS_ACCESS_KEY_ID }} 99 | password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 100 | - name: Checkout git repo 101 | uses: actions/checkout@v3 102 | - name: Docker metadata 103 | id: meta 104 | uses: docker/metadata-action@v3 105 | with: 106 | images: 263049488290.dkr.ecr.us-east-1.amazonaws.com/app 107 | - name: Build and Push Image to ECR 108 | uses: docker/build-push-action@v2 109 | with: 110 | push: true 111 | tags: ${{ steps.meta.outputs.tags }} 112 | labels: ${{ steps.meta.outputs.labels }} 113 | context: ./app 114 | 115 | [...] 116 | 117 | ``` 118 | 119 |

Now, we need to add these same credentials in the Uffizzi Dashboard. In Step 3 of 4 of the account setup guide, you are asked to connect to various external services, as shown below. Select the Sign in option for your registry provider(s) of choice, then enter your credentials. For example, to add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, select Sign in to Amazon Elastic Container Registry.

120 | 121 |
122 |

After account setup, you can make changes to your credentials by selecting Menu (three horizontal lines) > Settings > Integrations > CONFIGURE/DISCONNECT.

123 | 124 |
125 |
126 | 127 | That's it! Your pipeline is now configured to use Uffizzi. To test your pipeline, try opening a new pull request. 128 | 129 | ## Suggested articles 130 | 131 | * [Configure password-protected environments](password-protected.md) 132 | * [`UFFIZZ_URL` environment variable](../references/uffizzi-environment-variables.md) 133 | * [Set up single sign-on (SSO)](single-sign-on.md) 134 | -------------------------------------------------------------------------------- /docs/guides/container-registry-integrations.md: -------------------------------------------------------------------------------- 1 | # Authenticate with a container registry 2 | 3 | You can authenticate with the container registries you use in one of two ways, depending on which CI solution you choose: 4 | 5 | ## External CI 6 | 7 | If you're using an external CI provider, such as GitHub Actions, GitLab CI, or CircleCI, you must add registry credentials as secrets in your provider's interface. 8 | 9 | Uffizzi supports the following container registries: 10 | - Amazon ECR 11 | - Azure Container Registry (ACR) 12 | - Docker Hub 13 | - GitHub Container Registry (GHCR) 14 | - Google Container Registry (GCR) 15 | - Docker Registry (generic) 16 | 17 | 18 | See the following GitHub Actions example ([full example available here](https://github.com/UffizziCloud/example-voting-app/blob/8f78f9204c8869aca538cb929d49c5b1074da8ff/.github/workflows/uffizzi-previews.yml)) that passes a GitHub Container Registry access token to the [Uffizzi resuable workflow](https://github.com/marketplace/actions/preview-environments): 19 | 20 | === "GitHub Actions example" 21 | ``` yaml hl_lines="16" 22 | deploy-uffizzi-preview: 23 | name: Use Remote Workflow to Preview on Uffizzi 24 | needs: render-compose-file 25 | uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@v2.2.0 26 | if: ${{ github.event_name == 'pull_request' && github.event.action != 'closed' }} 27 | with: 28 | compose-file-cache-key: ${{ needs.render-compose-file.outputs.compose-file-cache-key }} 29 | compose-file-cache-path: docker-compose.rendered.yml 30 | username: adam+1@idyl.tech 31 | server: https://app.uffizzi.com 32 | project: my-application-c2e3 33 | secrets: 34 | password: ${{ secrets.UFFIZZI_PASSWORD }} 35 | url-username: admin 36 | url-password: ${{ secrets.URL_PASSWORD }} 37 | personal-access-token: ${{ secrets.GHCR_ACCESS_TOKEN }} 38 | permissions: 39 | contents: read 40 | pull-requests: write 41 | ``` 42 | 43 | 44 | ## Uffizzi CI 45 | If you're using Uffizzi CI, you can choose to add your application components from source code or as pre-built images pulled from a container registry. This guide describes the process of configuring Uffizzi to to pull and deploy images from your container registry. If your container registry provider is not listed below, [let us know](mailto:support@uffizzi.com). 46 | 47 | ### Amazon ECR 48 | 49 | To configure Uffizzi to pull images from your Amazon ECR, it is recommended that you first create a dedicated IAM user for this purpose. After creating this IAM user, add its credentials in the Uffizzi Dashboard. Finally, configure webhooks to send notifications to Uffizzi when you push new images to ECR. 50 | 51 |
Create IAM user to authorize Uffizzi to pull images from ECR 52 | 53 |

To fetch container images from your private ECR repositories, Uffizzi requires an API access key for an IAM User within your AWS Account. It's a best practice to grant this user only the permissions required. This section will walk you through creating a new IAM User, granting it strict permissions, and creating an API access key.

54 | 55 |

The easiest way to create this user is to use the AWS command-line interface (CLI). Make sure you have installed and configured the `aws` command on your workstation or container, including setting the default region to match your ECR repositories.

56 | 57 |

Create a new IAM User within your AWS Account. If you get an error that it already exists, that's fine.

58 | 59 | ``` 60 | aws iam create-user --user-name uffizzi --output table 61 | ``` 62 | 63 |

Attach an Amazon-managed policy to the new User. This grants permission only to list and read images.

64 | 65 | ``` 66 | aws iam attach-user-policy --user-name uffizzi --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly 67 | ``` 68 | 69 |

Create and obtain an API access key for this user. You'll need the output of this command soon.

70 | 71 | ``` 72 | aws iam create-access-key --user-name uffizzi --query "[join(' ', ['Access Key ID:', AccessKey.AccessKeyId]), join(' ', ['Secret Access Key:', AccessKey.SecretAccessKey])]" --output table 73 | ``` 74 | 75 |

When you configure ECR within Uffizzi in the next step, you'll need these values.

76 |
77 | 78 |
Add IAM user credentials in the Uffizzi Dashboard 79 | 80 |

In the Uffizzi Dashboard (UI), navigate to Settings > Integrations. There you will see a list that includes container registries supported by Uffizzi. Select CONFIGURE next to the Amazon ECR option.

81 | 82 | 83 | 84 |   85 |

When prompted, sign in to ECR with your registry domain, access key ID, and your secret access key. Once authenticated, Uffizzi will now be able to pull images from your registry.

86 | 87 | 88 | 89 |
90 | 91 |
Configure webhooks for Continuous Previews from ECR 92 | 93 |

After configuring AWS ECR to pull images, you'll probably also want to enable Continuous Previews when you push a new container image. This requires configuring AWS EventBridge to send Uffizzi notifications via webhook HTTP requests. This section will walk you through configuring these webhooks.

94 | 95 |

The easiest way to configure these webhooks is to use the AWS CLI. Make sure you have installed and configured the aws command on your workstation or container, including setting the default region to match your ECR repositories.

96 | 97 |

Download the following shell script to configure these webhooks for you:

98 | 99 | ``` 100 | wget https://raw.githubusercontent.com/UffizziCloud/docs/main/docs/assets/scripts/uffizzi_ecr_webhook_configure.bash 101 | ``` 102 | 103 | 104 |

Review the contents so you understand what you're executing. Then execute the script:

105 | 106 | ``` 107 | bash ./uffizzi_ecr_webhook_configure.bash 108 | ``` 109 | 110 |

You should see output about the resource you've just created. If you see errors about resources already existing that's fine; that means someone else has already configured them.

111 | 112 |

You should also see the EventBridge Rule and other resources within the AWS Console:

113 | 114 | 115 | 116 |

117 |
Removing webhook configuration 118 | 119 |

We've also provided a script to remove all of this configuration. Use this when you want to reconfigure the webhooks or when you no longer require automatic deployment to Uffizzi.

120 | 121 |

Download the removal script:

122 | 123 | ``` 124 | wget https://raw.githubusercontent.com/UffizziCloud/docs/main/docs/assets/scripts/uffizzi_ecr_webhook_remove.bash 125 | ``` 126 | 127 |

Review the contents so you understand what you're executing. Then execute the removal script:

128 | 129 | bash ./uffizzi_ecr_webhook_remove.bash 130 |
131 | 132 |
Removing IAM User 133 | 134 |

You can revoke Uffizzi's access to your ECR repositories by detaching the policy from the IAM User:

135 | 136 | 137 | ``` 138 | aws iam detach-user-policy --user-name uffizzi --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly 139 | ``` 140 | 141 |

If no longer needed, you can then delete the IAM User. You must first delete all of the user's API Access Keys.

142 |
143 | 144 | ### Azure Container Registry (ACR) 145 | 146 | To configure Uffizzi to pull images from your ACR, it is recommended that you first create a dedicated service principal for this purpose, along with an Application and Subscription. After creating these resources, add the service principal's credentials in the Uffizzi Dashboard. Finally, configure webhooks to send notifications to Uffizzi when new images or tags are pushed to ACR. 147 | 148 |
Create Azure service principal to authorize Uffizzi to pull images from ACR 149 | 150 |

To access your container images directly, Uffizzi requires access to your Azure Container Registry. The easiest way to accomplish this is to create a service principal and grant it the `ACRPull` role.

151 | 152 |

You may need to create an Application with a Subscription.

153 | 154 |

Once you have an active Subscription and a Container Registry, you can use the create-for-rbac command to create a service principal and simultaneously grant it the ACRPull role:

155 | 156 | ``` 157 | az ad sp create-for-rbac --name uffizzi-example-acrpull --scopes /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/uffizzi-example/providers/Microsoft.ContainerRegistry/registries/uffizziexample --role acrpull 158 | ``` 159 | 160 |

This command will output a JSON object with some values you will need later: appId and password. See the Azure CLI documentation for details about this command. 161 |

162 | 163 |
Add your Azure service principal in the Uffizzi Dashboard 164 |

To grant Uffizzi access to pull images from your ACR, you will need:

165 | 166 | 171 | 172 |

The Application ID and Password are provided in the output from the create-for-rbac command above, or they can be obtained within the Azure web portal.

173 | 174 |

Log in to the Uffizzi Dashboard (UI) and navigate to Settings > Integrations then select CONFIGURE next to the ACR option.

175 | 176 | 177 | 178 |   179 |

Enter your credentials when prompted, then click Sign in to Azure Container Registry. Uffizzi should now have access to pull images from your ACR.

180 | 181 | 182 | 183 |
184 | 185 |
Configure webhooks for Continuous Previews from ACR 186 | 187 |

If you've added images from ACR to a template or compose file, you'll probably also want to enable continuous previews when you push a new container image. This requires adding a webhook to send Uffizzi notifications. This section will walk you through configuring this webhook.

188 | 189 |

The easiest way to configure these webhooks is to use the Azure command-line interface (CLI). Make sure you have installed and configured the az command on your workstation or container.

190 | 191 |

First identify which ACR Registry you want to use for automatic deployments.

192 | 193 | ``` 194 | az acr list --output table 195 | ``` 196 | 197 |

Use the name of that registry when you add the webhook:

198 | 199 | ``` 200 | az acr webhook create --registry --name uffizzi --actions push --uri https://app.uffizzi.com/api/v1/webhooks/azure 201 | ``` 202 |
203 | 204 |
Removing webhook configuration 205 | 206 |

To stop sending notifications to Uffizzi, you can remove the webhook you configured above:

207 | 208 | ``` 209 | az acr webhook delete --registry --name uffizzi 210 | ``` 211 |
212 | 213 | ### GitHub Container Registry (GHCR) 214 | 215 | To configure Uffizzi to pull images from GHCR, you must first create an personal access token to provide to Uffizzi. Once authorized, Uffizzi will automatically configure webhooks on your registry to be notified when you push new images. 216 | 217 |
Create a personal access token for GHCR 218 | 219 |

To create a GitHub personal access token follow these instructions. Your token needs read:packages scope. 220 | 221 |

222 | 223 |
Authorize Uffizzi to pull container images from GHCR 224 | 225 |

Log in to the Uffizzi Dashboard and navigate to Settings > Integrations, then select CONFIGURE next to the GitHub Container Registry option.

226 | 227 | 228 | 229 |

Enter your GitHub username and the personal access token you created, then select Sign in to GitHub Container Registry. Uffizzi should now have access to pull images from your GHCR registry. Uffizzi will automatically configure a webhook to be notified when you push new images.

230 | 231 | 232 | 233 |
234 | 235 |
Deleting the personal access token for GHCR 236 | 237 |

Log in to your GitHub account, then navigate to Settings > Developer settings > Personal access tokens. Then select Delete for the token you want to delete. This will revoke Uffizzi's access to your GHCR registry.

238 | 239 | 240 | 241 |
242 | 243 | 244 | ### Google Container Registry (GCR) 245 | 246 | To configure Uffizzi to pull images from your GCR, you need to add your GCR key file in the Uffizzi Dashboard (UI). Once added, configure a webhook to send notifications to Uffizzi when you push new images to GCR. 247 | 248 |
Authorize Uffizzi to pull container images from GCR 249 | 250 |

To grant Uffizzi access to pull images from your GCR, you will need a JSON key file.

251 | 252 |

Log in to the Uffizzi Dashboard and navigate to Settings > Integrations, then select CONFIGURE next to the GCR option.

253 | 254 | 255 |   256 | 257 |

Upload or copy and paste your key file when prompted, then click Add GCR Key File. Uffizzi should now have access to pull images from your GCR.

258 | 259 | 260 | 261 | 262 |
263 | 264 |
Configure webhooks for continuous previews from GCR 265 | 266 |

If you've added images from GCR to a template or compose file, you'll probably also want to enable continuous previews when you push a new container image. This requires adding a webhook to send Uffizzi notifications. This section will walk you through configuring this webhook.

267 | 268 |

The easiest way to configure these webhooks is to use the Google Cloud command-line interface (CLI). Make sure you have installed and configured the gcloud command on your workstation or container.

269 | 270 |

First, create a Topic on Google's Pub/Sub API:

271 | 272 | ``` 273 | gcloud pubsub topics create gcr 274 | ``` 275 | 276 |

Then configure a Subscription to notify Uffizzi:

277 | 278 | ``` 279 | gcloud pubsub subscriptions create uffizzi-gcr-webhook --topic=gcr --push-endpoint=https://app.uffizzi.com/api/v1/webhooks/google --expiration-period=never --message-retention-duration=10m 280 | ``` 281 | 282 |

If these commands fail, make sure you have enabled the Pub/Sub API for your Google Cloud Project. You may also need to specify --project if you have multiple Google Cloud Projects.

283 | 284 |

Learn more about configuring notifications from GCR.

285 | 286 |
287 | 288 |
Removing Webhook Configuration 289 | 290 |

To stop sending notifications to Uffizzi, you can remove the webhook you configured above:

291 | 292 | ``` 293 | gcloud pubsub subscriptions delete uffizzi-gcr-webhook 294 | ``` 295 | 296 |

If this was your only Subscription to the GCR Topic, you could also delete that Topic.

297 | 298 |

If that was your only Topic, you could also disable the Pub/Sub API.

299 | 300 |
301 | 302 | ### Docker Hub 303 | 304 | To configure Uffizzi to pull images from your private Docker Hub registry, it is recommended that you first create an Access Token to provide to Uffizzi. Once authorized, Uffizzi will automatically configure webhooks on your registry to be notified when you push new images. 305 | 306 |
Create an access token for Docker Hub 307 | 308 |

Log in to Docker Hub, then navigate to Account Settings > Security and select the New Access Token button. In the Access Token Description field, enter "uffizzi" or a similar description. For Access permissions choose Read-only, then select Generate to create your Access Token.

309 | 310 | 311 | 312 |

On the next screen, you should see your Accesss Token. Save this value, as you will need it in the next step.

313 | 314 | 315 | 316 |
317 | 318 |
Authorize Uffizzi to pull container images from Docker Hub 319 | 320 |

Log in to the Uffizzi Dashboard and navigate to Settings > Integrations, then select CONFIGURE next to the Docker Hub option.

321 | 322 | 323 | 324 |

Enter your Docker ID and the access token you created, then select Sign in to Docker Hub. Uffizzi should now have access to pull images from your Docker Hub registry. Uffizzi will automatically configure a webhook to be notified when you push new images.

325 | 326 | 327 | 328 |
329 | 330 |
Deleting the access token for Docker Hub 331 | 332 |

Log in to Docker Hub, then navigate to Account Settings > Security. Select the the checkbox next the access token you added in the Uffizzi Dashboard, then select Delete and Delete Forever to confirm. 333 | 334 | 335 | 336 | 337 | 338 | 339 |

340 | -------------------------------------------------------------------------------- /docs/guides/demo-on-uffizzi.md: -------------------------------------------------------------------------------- 1 | # **Demo on Uffizzi** button 2 | 3 | Add the **Demo on Uffizzi** button to your repository's `README.md` to give visitors a fast way to interact with your application in a live demo environment. This button requires **no configuration** by your users, and it **does not** require them to have a Uffizzi account. 4 | 5 | ![Demo](https://storage.googleapis.com/cdn.uffizzi.com/demo-button.svg) 6 | 7 | !!! Note 8 | The **Demo on Uffizzi** button is currently available only to Uffizzi [Open Source Plan](https://www.uffizzi.com/pricing) customers—i.e. it will not work on any arbitrary repo. Open source maintainers can [contact us on Slack](https://join.slack.com/t/uffizzi/shared_invite/zt-ffr4o3x0-J~0yVT6qgFV~wmGm19Ux9A) to configure this for their projects. 9 | 10 | ## How it works 11 | 12 | For qualifying projects, Uffizzi creates a public route of the the form `https://app.uffizzi.com/demo/github.com//`. When a user visits this endpoint (by clicking on the demo button), Uffizzi checks that a demo Compose file (`docker-compose.demo.uffizzi.yml`) is configured for the project. If it exists, Uffizzi will deploy this configuration to a demo environment. 13 | 14 | ``` 15 | [![Demo](https://cdn.uffizzi.com/demo-button.svg)](https://app.uffizzi.com/demo/github.com//) 16 | ``` 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/guides/docker-compose-template.md: -------------------------------------------------------------------------------- 1 | # Create a Docker Compose template 2 | 3 | In this section, we'll create a template using [Docker Compose](https://docs.docker.com/compose/compose-file/) that describes our application configuration. Uffizzi uses Docker Compose as its configuration format because it is relatively simple and widely used by developers. 4 | 5 | !!! note 6 | Uffizzi supports a subset of the [Compose specification](https://github.com/compose-spec/compose-spec/blob/master/spec.md). For a full list of supported keywords, see the [Uffizzi Compose file reference](../references/compose-spec.md). 7 | 8 | ## Configure your Compose to dynamically update image definitions 9 | The Uffizzi environment creation step typically executes at the end of a CI pipeline after a series of steps that are triggered by an event, such as a pull request or new commit. If you don't have an existing CI solution, Uffizzi CI can build your application from source and store your container images for you (Note: Your source code must be stored in a GitHub repository to use Uffizzi CI). Alternatively, if you're using an external CI service, such as GitHub Actions or CircleCI, you will need to tell Uffizzi where your images are stored and how to access them. 10 | 11 | Each time your CI pipeline builds and pushes new images, Uffizzi needs access to them. This means that we need to dynamically update our compose file `service` definitions with the new image names and tags each time our pipeline runs. To do this, we'll follow one of two methods, depending on which CI solution you choose: 12 | 13 | - **Uffizzi CI** - If you want to use Uffizzi CI, you can simply define a `build` context that points to your source code repository on GitHub and let Uffizzi handle building and tagging images and updating your Compose. See the [Uffizzi Compose file reference](../references/compose-spec.md#build) for `build` and `context` details. 14 | 15 | - **External CI** - If you're using an external CI provider such as GitHub Actions or GitLab CI, you can use variable substitution to pass the output from your CI build step, i.e. `image:tag`, to your Compose file `image` definition (See highlighted example below). This solution is discussed in detail in the [next section](integrate-with-ci.md). 16 | 17 | === "Uffizzi CI" 18 | 19 | ``` yaml hl_lines="3-5" title="docker-compose.uffizzi.yml" 20 | services: 21 | app: 22 | build: 23 | context: https://github.com/example/app 24 | dockerfile: Dockerfile 25 | environment: 26 | PGUSER: "postgres" 27 | PGPASSWORD: "postgres" 28 | deploy: 29 | resources: 30 | limits: 31 | memory: 250M 32 | 33 | db: 34 | image: postgres:9.6 35 | environment: 36 | POSTGRES_USER: "postgres" 37 | POSTGRES_PASSWORD: "postgres" 38 | ``` 39 | 40 | === "External CI (e.g. GitHub Action)" 41 | 42 | ``` yaml hl_lines="3" title="docker-compose.uffizzi.yml" 43 | services: 44 | app: 45 | image: "${APP_IMAGE}" # Output of build step stored as environment variable 46 | environment: 47 | PGUSER: "${PGUSER}" 48 | PGPASSWORD: "${PGPASSWORD}" 49 | deploy: 50 | resources: 51 | limits: 52 | memory: 250M 53 | 54 | db: 55 | image: postgres:9.6 56 | environment: 57 | POSTGRES_USER: "${PGUSER}" 58 | POSTGRES_PASSWORD: "${PGPASSWORD}" 59 | ``` 60 | 61 | ## Define an Ingress for your application 62 | 63 | Whether using Uffizzi CI or an external CI provider, Uffizzi needs to know which of your application services will receive incoming traffic. This "Ingress" is an HTTPS load balancer that will forward HTTP traffic to one of the defined `services`. Along with the service name, you must indicate on which port the target container is listening. The `ingress` must be defined within an `x-uffizzi` [extension field](https://docs.docker.com/compose/compose-file/compose-file-v3/#extension-fields) as shown in the example below: 64 | 65 | ``` yaml hl_lines="1-5" title="docker-compose.uffizzi.yml" 66 | # This block tells Uffizzi which service should receive HTTP traffic. 67 | x-uffizzi: 68 | ingress: 69 | service: app 70 | port: 80 71 | 72 | # My application 73 | services: 74 | app: 75 | image: "${APP_IMAGE}" # Output of build step stored as environment variable 76 | environment: 77 | PGUSER: "${PGUSER}" 78 | PGPASSWORD: "${PGPASSWORD}" 79 | deploy: 80 | resources: 81 | limits: 82 | memory: 250M 83 | 84 | db: 85 | image: postgres:9.6 86 | environment: 87 | POSTGRES_USER: "${PGUSER}" 88 | POSTGRES_PASSWORD: "${PGPASSWORD}" 89 | ``` 90 |   91 | 92 | !!! Tip 93 | If you need to expose multiple public routes for your application, see this article [Exposing multiple routes](expose-multiple-routes.md). 94 | 95 | ## Add secrets in your CI platform (optional) 96 | 97 | You may also want to move sensitive information like credentials out of your Docker Compose file before commiting it to a remote repository. Most CI providers offer a way to store secrets and then reference them in the steps of your pipeline. To do this, we'll follow one of two methods, depending on which CI solution you choose: 98 | 99 | - **Uffizzi CI** - If you want to use Uffizzi CI, you can create read-only secrets in the Uffizzi Dashboard web interface (this process is described in detail in [Section 3](configure-credentials.md)), then reference them using the `external` keyword, as shown below. For details on `secrets` and `external` configuration options, see the [Uffizzi Compose file reference](../references/compose-spec.md#nested-secrets). 100 | 101 | - **External CI** - If you're using an external CI provider, you can store the secrets using your provider's interface and then reference them via variable substitution within an `environment` definition (See highlighted example below). This solution is discussed in detail in the [next section](integrate-with-ci.md). 102 | 103 |
GitHub Actions example 104 |

In GitHub, navigate to your repository, then select Settings > Secrets > Actions > New repository secret. Alternatively, you can [use the GitHub CLI](https://cli.github.com/manual/gh_secret).

105 | 106 | 107 |
108 | 109 |
110 |
111 | 112 | === "Uffizzi CI" 113 | 114 | ``` yaml hl_lines="20-32" title="docker-compose.uffizzi.yml" 115 | # This block tells Uffizzi which service should receive HTTPS traffic 116 | x-uffizzi: 117 | ingress: 118 | service: app 119 | port: 80 120 | 121 | services: 122 | app: 123 | build: 124 | context: https://github.com/example/app 125 | dockerfile: Dockerfile 126 | secrets: 127 | - pg_user 128 | - pg_password 129 | deploy: 130 | resources: 131 | limits: 132 | memory: 250M 133 | 134 | db: 135 | image: postgres:9.6 136 | secrets: 137 | - pg_user 138 | - pg_password 139 | 140 | secrets: 141 | pg_user: 142 | external: true 143 | name: "POSTGRES_USER" 144 | pg_password: 145 | external: true 146 | name: "POSTGRES_PASSWORD" 147 | ``` 148 | 149 | === "External CI (e.g. GitHub Actions)" 150 | 151 | ``` yaml hl_lines="20-22" title="docker-compose.uffizzi.yml" 152 | # This block tells Uffizzi which service should receive HTTPS traffic 153 | x-uffizzi: 154 | ingress: 155 | service: app 156 | port: 80 157 | 158 | services: 159 | app: 160 | image: "${APP_IMAGE}" # Output of build step stored as environment variable 161 | environment: 162 | PGUSER: "${PGUSER}" 163 | PGPASSWORD: "${PGPASSWORD}" 164 | deploy: 165 | resources: 166 | limits: 167 | memory: 250M 168 | 169 | db: 170 | image: postgres:9.6 171 | environment: 172 | POSTGRES_USER: "${PGUSER}" 173 | POSTGRES_PASSWORD: "${PGPASSWORD}" 174 | ``` 175 | 176 | ## Commit your template to your repository 177 | 178 | Once you're finished creating your Docker Compose template, commit it to your repository and push. 179 | 180 | ## Next article 181 | 182 | [Integrate with your CI pipeline](integrate-with-ci.md) 183 | -------------------------------------------------------------------------------- /docs/guides/environment-variables.md: -------------------------------------------------------------------------------- 1 | # Add environment variables 2 | 3 | Environment variables are name/value pairs that are dynamically loaded into your containers at runtime. They are often used to pass configuration details to your application. Using environment variables instead of hard-coded values lets you keep environment-specific details out of your source code. 4 | 5 | You will add secrets in one of two ways, depending on which CI solution you choose: 6 | 7 | ## External CI 8 | 9 | If you're using an external CI provider, such as GitHub Actions, GitLab CI, or CircleCI, environment variables should be stored via your provider's interface and referenced in your [Docker Compose template](docker-compose-template.md) using the [`environment`](../references/compose-spec.md#environment) element. 10 | 11 | 12 | !!! note 13 | Docker Compose element [`env_file`](../references/compose-spec.md#env_file) is not currently support for external CI providers. 14 | 15 | ## Uffizzi CI 16 | 17 | If you're using Uffizzi CI, you have two options for adding environment variables in your [Uffizzi Compose file](../references/compose-spec.md): `environment` or `env_file`. 18 | 19 | * Use [`environment`](../references/compose-spec.md#environment) if you have a small number of environment variables to add. You can list your variables in an `environment` block within the service definition. For example, the following `docker-compose.uffizzi.yml` snippet adds two environment variables, `FOO` and `BAR`, to the `myservice` container: 20 | ```yaml 21 | services: 22 | mysevice: 23 | image: example/myservice:latest 24 | environment: 25 | FOO: bar 26 | BAR: baz 27 | ``` 28 | 29 | * Use [`env_file`](../references/compose-spec.md#env_file) if you have a large number of enviroment variables that would otherwise clutter up your compose file. You can store your variables in a file within your repository and use the `env_file` component to specify the path to this file. For example, the following `docker-compose.uffizzi.yml` snippet tells Uffizzi to read the contents of `envs/myconfigs.env` and add them to the container `myservice`: 30 | ```yaml 31 | services: 32 | mysevice: 33 | image: example/myservice:latest 34 | env_file: ./envs/myconfigs.env 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/guides/expose-multiple-routes.md: -------------------------------------------------------------------------------- 1 | # Expose multiple routes for your application 2 | 3 | ## Understanding Uffizzi `ingress` 4 | For each ephemeral environment, Uffizzi provisions one _https_ load balancer to receive incoming traffic for your application. This "`ingress`" is defined in your Docker Compose file and requires a `service` and `port` definition, as shown in the example below. 5 | 6 | ``` yaml 7 | x-uffizzi: 8 | ingress: 9 | service: app 10 | port: 80 11 | 12 | services: 13 | app: 14 | ... 15 | ``` 16 | 17 | ## Exposing multiple routes 18 | 19 | Uffizzi allows only one `service` to act as your `ingress`, but your application may have multiple services you want to expose. For example, you may want to serve your main application at `/` and a console at `/console`. To do this, you can add a new `nginx` service to your configuration to map requests for specific ports to their target containers. We'll first add an `nginx` service to the Docker Compose file, then configure it as the `ingress`. Finally, we'll define the routes in an `nginx.conf` file. 20 | 21 | ```yaml title="docker-compose.uffizzi.multiple-routes.yml" 22 | x-uffizzi: 23 | ingress: 24 | service: nginx 25 | port: 8081 26 | 27 | services: 28 | nginx: 29 | image: nginx:alpine 30 | ports: 31 | - "8081:8081" 32 | volumes: 33 | - ./uffizzi/nginx:/etc/nginx/conf.d/ 34 | 35 | app: 36 | ports: 37 | - 3001:3001 38 | 39 | api: 40 | ports: 41 | - 7001:7001 42 | ``` 43 | 44 |   45 | 46 | Now we will create a new file in our repository `/uffizzi/nginx/nginx.conf` that defines how our paths will be exposed. By default the official `nginx:latest` base image we used in our Docker Compose file will include all `/etc/nginx/conf.d/*.conf` files. 47 | 48 | Here we assume that `app` is listening for connections on `3001` and `3002` for the main applicaiton and console, respectively. If requests for port `:3001` are received, we tell `nginx` to forward those requests to `/`. If requests for port `3002` are received, we tell `nginx` to forward those requests to `/console`. 49 | 50 | ```json title="nginx.conf" 51 | 52 | http { 53 | server { 54 | listen 8081; 55 | 56 | location / { 57 | proxy_pass http://localhost:3001; 58 | } 59 | 60 | location /console/ { 61 | proxy_pass http://localhost:3002; 62 | } 63 | } 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/guides/github-environment.md: -------------------------------------------------------------------------------- 1 | # Create a GitHub Environment for your previews 2 | [GitHub Environments](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) are a convenient way to collect all of your previews in a single view on GitHub. Specifically, GitHub Environments are the target of your workflows, so you can configure a "uffizzi" Environment to be the target of your ephemeral preview deployments. You'll also see these deployments appear in your Actions workflow graph. 3 | 4 | 5 |
6 | 7 |
8 | 9 | 10 | ## Set up a "uffizzi" GitHub Environment 11 | If you're using the standard [Uffizzi reusable workflow](https://github.com/marketplace/actions/preview-environments) to create, update, and delete environments on pull request events, then you just need to create a GitHub Environment called "uffizzi" in your reposiory via the GitHub UI. The reusable workflow is pre-configured to populate this Environment with Uffizzi preview deployments. If you're not using the resuable workflow, you'll need to configue the `jobs..environment` key as described [here](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#using-an-environment). 12 | 13 | Login to GitHub, then navigate to your repository **Settings** > **Environments** and select **New environment**. For the Environmnet name enter "**uffizzi**". Note that if you name it something else, it won't work since the reusable workflow expects the enviroment to be named "uffizzi". 14 | 15 | That's it! You can now select the "uffizzi" Environment to see the new Deployments that are created every time your Uffizzi workflow runs. 16 | 17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /docs/guides/logs.md: -------------------------------------------------------------------------------- 1 | # Check logs 2 | 3 | Three types of logs are available in Uffizzi: container logs, build logs and event logs. 4 | 5 | **Container logs** - Also known as runtime logs, container logs are output from the application itself, including its dependencies. Container logs capture stdout, allowing you to inspect the activity of your application. Anything you would typically see in a terminal running your app locally is shown here. If you have trouble getting your app running on Uffizzi or connecting to a database, container logs are often the best place to start troubleshooting. 6 | 7 | **Build logs** - When building your application from source (e.g. GitHub), Uffizzi displays logs from this process in the the Build Logs feed. If you have trouble getting your app to build on Uffizzi, build logs may provide you with enough information to troubleshoot your issue. 8 | 9 | To view either container logs or build logs, first navigate to the desired preview in the Uffizzi Dashboard, then select the container whose logs you want to view. You can toggle between the container and build logs in the left-hand menu: 10 | 11 | ![logs-screenshot](../assets/images/logs.png) 12 | 13 |   14 | 15 | **Event logs** - These are Kubernetes events that are provided by the Kubernetes API. Uffizzi displays these logs in the Event Log feed. To view event logs, first navigate to the desired preview in the Uffizzi Dashboard, then select the **Event Log** option from the left-hand menu: 16 | 17 | ![event-logs-screenshot](../assets/images/event-logs.png) 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/guides/password-protected.md: -------------------------------------------------------------------------------- 1 | # Password-protected environments 2 | 3 | Uffizzi allows you to configure a username and password for your Preview Environments to limit who has access to them. This feature is enabled per project, so anyone navigating to the URL of any Preview Environment of that project, either via a web browser or with a command like `curl`, must enter valid credentials to gain access. To configure this feature, you must be an account [Owner](../topics/rbac.md#owner). 4 | 5 | Select your CI provider to begin set up: 6 | 7 | [Uffizzi CI ⬇](#configure-password-protection-for-uffizzi-ci) 8 | [GitHub Actions ⬇](#configure-password-protection-for-github-actions) 9 | 10 | ## Configure password protection for Uffizzi CI 11 | 1. In the Uffizzi Dashboard, navigate to your project, then select **Project Settings** > **Password protection** > **Edit** > **Enabled** (toggle). 12 |
Click to expand 13 | 14 |
15 | 2. Enter a username and password, then select **Save**. 16 | 17 | Password protection will now be enabled for all environments belonging to this project, including any pre-existing environments. To access these Preview Environments, you can pass your credentials via the [web browser](#access-via-web-browser) or [`curl` command](#access-via-curl). 18 | 19 | ## Configure password protection for GitHub Actions 20 | 1. In the Uffizzi Dashboard, navigate to your project, then select **Project Settings** > **Password protection** > **Edit** > **Enabled** (toggle). 21 |
Click to expand 22 | 23 |
24 | 2. Enter a username and password, then select **Save**. 25 | 3. Store credentials as GitHub Actions secrets. 26 |   27 | In GitHub, navigate to your repository. Then select **Settings** > **Secrets and variables** > **Actions** > **Secrets** (tab) > **New repository secret**. (_Be sure you add a new repository **secret** from the **Secrets** tab, not a new repository **variable** from the **Variables** tab_). Add a secret name and value, then select **Add secret**. 28 |
Click to expand 29 | 30 | 31 |
32 | 4. Pass credentials as parameters in your preview job. 33 |   34 | If you are using the official Uffizzi [preview action](https://github.com/marketplace/actions/preview-environments) with the [reusable workflow](https://github.com/UffizziCloud/preview-action/blob/master/.github/workflows/reusable.yaml), you will also need to pass the environment username and password to the reusable workflow via [`url-username`](https://github.com/marketplace/actions/preview-environments#url-username-and-url-password) and [`url-password`](https://github.com/marketplace/actions/preview-environments#url-username-and-url-password) parameters. These credentials are used by the preview action (and Uffizzi) to perform health checks on your Preview Environments. You can see example usage [here](https://github.com/UffizziCloud/example-voting-app/blob/8f78f9204c8869aca538cb929d49c5b1074da8ff/.github/workflows/uffizzi-previews.yml#L179-L180). 35 |   36 | ``` yaml hl_lines="9 10" title="uffizzi-preview.yaml" 37 | deploy-uffizzi-preview: 38 | name: Use Remote Workflow to Preview on Uffizzi 39 | needs: render-compose-file 40 | uses: UffizziCloud/preview-action/.github/workflows/reusable.yaml@v2.2.0 41 | if: ${{ github.event_name == 'pull_request' && github.event.action != 'closed' }} 42 | with: 43 | ... 44 | secrets: 45 | url-username: ${{ secrets.URL_USERNAME }} 46 | url-password: ${{ secrets.URL_PASSWORD }} 47 | permissions: 48 | ... 49 | ``` 50 | 51 | Password protection will now be enabled for all environments belonging to this project, including any pre-existing environments. To access these Preview Environments, you can pass your credentials via the [web browser](#access-via-web-browser) or [`curl` command](#access-via-curl). 52 | 53 | ## Access via web browser 54 | If you visit the preview URL in a browser, you can enter the environment username and password in the _http_ dialog window, as shown in the screenshot below. Select **Log in** to be redirected to the Preview Environment. 55 | 56 | ![HTTP dialog window](../assets/images/http-dialog.webp) 57 | ## Access via `curl` 58 | You can access a password-protected environment via the `curl` command by passing the environment username and password as an argument. For example: 59 | 60 | ``` 61 | curl -u "username:password" [PREVIEW_URL] 62 | ``` 63 | 64 | !!! Note 65 | The official Uffizzi [preview action](https://github.com/marketplace/actions/preview-environments) uses the `curl` command to check for successful deployments of Preview Environments. You can see how the Uffizzi preview action performs this check [here](https://github.com/UffizziCloud/preview-action/blob/599ea1a94a5ee8bca85843f9ec40524778e14cfc/.github/workflows/reusable.yaml#L284-L287). 66 | 67 | ## Suggested articles 68 | * [Set up single sign-on (SSO)](single-sign-on.md) 69 | * [Configure role-based access (RBAC)](../topics/rbac.md) 70 | * [Check the logs](logs.md) 71 | -------------------------------------------------------------------------------- /docs/guides/secrets.md: -------------------------------------------------------------------------------- 1 | # Secrets 2 | 3 | Secrets provide a mechanism for securely adding sensitive data, such as passwords, tokens, or keys, to the containers of a preview environment. Secrets are similar to environment variables, but they are intended for confidential data. Secrets are defined as name/value pairs and are injected at runtime. 4 | 5 | You can add secrets in one of two ways, depending on which CI solution you choose: 6 | 7 | ## External CI 8 | 9 | If you're using an external CI provider, such as GitHub Actions, GitLab CI, or CircleCI, secrets should be stored via your provider's interface and referenced in your compose file using the [`environment`](../references/compose-spec.md#environment) element with variable substitution. 10 | 11 | In the following example, `PG_USER` and `PG_PASSWORD` are stored using [GitHub Actions secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) and referenced using variable substitution in a [Docker Compose template](docker-compose-template.md). 12 | 13 | See the [Uffizzi resuable workflow](https://github.com/marketplace/actions/preview-environments) for example usage. 14 | 15 | === "GitHub Actions" 16 | 17 | ``` yaml 18 | secrets: 19 | username: ${{ secrets.PG_USER }} 20 | password: ${{ secrets.PG_PASSWORD }} 21 | ``` 22 | 23 | === "Docker Compose Template" 24 | 25 | ``` yaml 26 | services: 27 | postgres: 28 | image: postgres:9.6 29 | environment: 30 | POSTGRES_USER: "${PGUSER}" 31 | POSTGRES_PASSWORD: "${PGPASSWORD}" 32 | deploy: 33 | resources: 34 | limits: 35 | memory: 500M 36 | ``` 37 | 38 | ## Uffizzi CI 39 | 40 | ### Add secrets in the Uffizzi Dashboard (app.uffizzi.com) 41 | If you're using Uffizzi CI, secrets can be added in the Uffizzi Dashboard (**Project** > **Project Settings** > **Secrets**). Once added, they cannot be viewed or edited. To update a Secret, you should delete the old Secret and create a new one. Secrets added in the **Project Settings** are available to all Preview environments in that project. 42 |   43 | 44 | ![](../assets/images/secrets.png) 45 | 46 | ### Add `secrets` element to your Docker Compose template 47 | 48 | In your Docker Compose, add the `secrets` and `external` elements as show in the example below. Be sure that your secrets are added in the Uffizzi Dashboard. If the external secret does not exist, you will see a secret-not-found error message in the Uffizzi Dashboard. 49 | 50 | - `external`: Indicates that the secret object (a name/value pair) is declared in the Uffizzi Dashboard (UI). Value must be `true`. 51 | - `name`: The name of the secret object in Uffizzi. 52 | 53 | In the following example, `POSTGRES_USER` and `POSTGRES_PASSWORD` are the names of secrets that have been added in the Uffizzi Dashboard. Their respective values are available to the `db` service once the stack is deployed. 54 | 55 | === "Uffizzi CI" 56 | 57 | ``` yaml 58 | services: 59 | db: 60 | image: postgres:9.6 61 | secrets: 62 | - pg_user 63 | - pg_password 64 | 65 | secrets: 66 | pg_user: 67 | external: true 68 | name: "POSTGRES_USER" 69 | pg_password: 70 | external: true 71 | name: "POSTGRES_PASSWORD" 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/guides/set-up-your-account.md: -------------------------------------------------------------------------------- 1 | # Set up your account 2 | 3 | ## From GitHub Actions 4 | When you run a GitHub Actions workflow that calls the Uffizzi [preview action](https://github.com/marketplace/actions/preview-environments), a Uffizzi account will be automatically created from your GitHub username. This happens because Uffizzi receives a signed [OIDC token](../topics/oidc.md) from GitHub that verifies your identity. There is no need to create a Uffizzi account before running the workflow. Afterwards when you sign in to _uffizzi.com_, you will see that your account already exists. 5 | 6 | !!! Important 7 | When a preview workflow is first merged into your [default branch](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository/changing-the-default-branch), the workflow run will fail. This is expected behavior since the preview workflow must be _initiated from the default branch_ of the base repository. That is, this workflow must first be merged into the default branch for subsequent workflow runs to succeed. 8 | 9 | ## From uffizzi.com 10 | You can alternatively go to [uffizzi.com](https://uffizzi.com) and use the **Sign up with GitHub** button to create an account with your GitHub login. When you do this, you will be redirected to the GitHub OAuth page, which includes a warning that Uffizzi may "Act on your behalf" (See screenshot below). Note that this is part of the standard permissions for GitHub OAuth. The warning is misleading because Uffizzi is only requesting read-only access to your email address and username at this step to set up your account. 11 | 12 | 13 | 14 | After selecting **Authorize Uffizzi Cloud**, you are asked to **Install & Authorize** the Uffizzi GitHub App, where you can see which permissions Uffizzi is requesting. Uffizzi requests only the minimum permissions it needs. The only way Uffizzi acts on your behalf is by commenting on PRs. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/guides/single-sign-on.md: -------------------------------------------------------------------------------- 1 | # Single sign-on (SSO) 2 | 3 | Single sign-on allows you to require that members of your organization sign in to the Uffizzi Dashboard via your Identity Provider. Uffizzi is compatible with any Identity Provider that supports both the SAML and OpenID Connect protocols. We currently have out-of-the-box support for the following SSO Identity Providers: 4 | 5 | * ADFS 6 | * Azure AD 7 | * Google SAML 8 | * Okta 9 | * OneLogin 10 | * OpenID 11 | * PingIdentity 12 | * SAML (generic) 13 | * VMWare 14 | 15 | ## Configure SSO 16 | 17 | Follow these steps to configure SSO on Uffizzi: 18 | 19 | 1. Create an account with email/password at [app.uffizzi.com](https://app.uffizzi.com/sign_in). By default, the user that creates an account will become an account [Admin](../rbac/#admin). 20 | 2. Once your account is created and you are logged in to the Uffizzi Dashboard, select the menu icon in the top left corner (the three horizontal lines). Then navigate to **Settings** -> **Single Sign-On (SSO)**. 21 | 3. In the text field provided, enter the domain associated with your organization's email addresses. For example if your email address format is name@acme.com, then enter *acme.com* in the domain field. Once you've entered your domain, select **ADD DOMAIN**. 22 | 4. Select **CONFIGURE SSO**. This will route you to a setup guide that includes configuration instructions specific to your Identity Provider. Once you complete the setup guide, you will be routed back to the Uffizzi Dashboard. 23 | 5. If your configuration was successful, you should see a confirmation message. If so, SSO is now configured for your account. Your teammates will now be required to sign in to the Uffizzi Dashboard with SSO. On the Uffizzi sign in page, they should select the **SIGN IN WITH SSO** option. 24 | 6. If there is a problem with your SSO connection, you can reset your configuration by selecting the **CONFIGURE SSO** button again and then selecting **Reset Connection** in the setup guide. 25 | 26 | ## Sign in with SSO 27 | 28 | Once configured, your team members must authenticate via [app.uffizzi.com](https://app.uffizzi.com/sign_in_sso) with the **Sign in with SSO** option. Our SSO implementation does not support signing in from your Identity Provider portal since IDP-initiated authentication is [vulnerable to man-in-the-middle attacks](https://workos.com/blog/sp-initiated-sso-vs-idp-authentication). We recommended that you disable the Uffizzi sign in option in your IdP's portal. 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/guides/support-microservices-in-ephemeral-environments-with-nginx.md: -------------------------------------------------------------------------------- 1 | # Support microservices in ephemeral environments with Nginx 2 | 3 | **A guide on how you can support your microservices architecture on Uffizzi ephemeral environments through Nginx** 4 | 5 | By [Shruti Chaturvedi](https://github.com/ShrutiC-git) 6 | 7 | ## **Nginx with Uffizzi: What problems can it solve?** 8 | 9 | Uffizzi, being cloud-native, allows you to bring your microservices architecture into ephemeral environments. The services directive is used to start each of the microservices defined in the `docker-compose.uffizzi.yml` file in its own container. This allows you to develop and manage the microservices as containers, independently of each other, in your ephemeral environments independently of each other. 10 | 11 | The next component of the microservices architecture is networking. How you configure networking for your ephemeral environments depends on your application architecture. If you have multiple independent client-side and server-side services talking through HTTP/S, for example, an Angular frontend talking to Node backend, networking between these services can be achieved using Nginx as a reverse proxy. Some other cases where we’ve used Nginx to help projects onboard to ephemeral environments are: 12 | 13 | - More than one microservice exposed publicly: if your application has multiple public-facing services, you’ll need to put them behind Nginx (or an alternate reverse proxy such as Traefik). The reverse proxy will receive your traffic, and route requests for different services accordingly. Currently, Uffizzi does not support adding multiple "ingresses" (multiple entry ports) into your application. For example, if you have one service named personal-account, exposed publicly on port `3000`, and another service named team-account, exposed publicly on port `3001`, natively (without Nginx), you can expose either `3000` or `3001` on your ephemeral environment to receive external requests using the [ingress field in your compose file](../references/compose-spec/#ingress-required). With Nginx added, you can put both services behind Nginx, expose Nginx to receive HTTP/S traffic, and forward requests coming to Nginx to your services. 14 | 15 | - More than one port needs to be accessed publicly (primarily applicable for monoliths): if a service has more than one exposed port that needs to be accessed publicly, adding Nginx as a reverse proxy will help you achieve this elegantly. 16 | 17 | ## **Example Application** 18 | Let’s take a look at an example of configuring a microservices application with Nginx. This example is a simple voting app, where users can cast a vote for dogs or cats and see the results of the polling in real-time. You can follow the [example on GitHub](https://github.com/UffizziCloud/quickstart). The application has 5 different microservices: 19 | 20 | 1. **`voting-app` service**: client-side service in Python, that allows you to cast a vote. Writes to our Redis queue 21 | 22 | 2. **`redis` service** - Redis queue to collect new votes 23 | 24 | 3. **`worker` service** - .NET Core worker service to consume votes from the Redis queue and write to Postgres 25 | 26 | 4. **`db` service** - Postgres DB, backed by a Docker volume, to write and read the votes 27 | 28 | 5. **`result-app`** service - Node.js web app that reads data from the db service and displays the results in real-time. 29 | 30 | ![Voting application microservices architecture](../assets/images/voting-app-architecture.webp) 31 | 32 | In this example, we have two services exposed publicly: the `voting-app` service, which receives votes, and the `result-app` service, which displays the results back to the user. As mentioned before, currently, Uffizzi supports defining a single service in your ephemeral environment to receive external requests. However, adding Nginx into the environment will solve the problem. 33 | 34 | We will define Nginx as the ingress into the ephemeral environments to listen to incoming HTTP/S connections and route the request to one of the two exposed services based on the path requested. 35 | 36 | ![Voting application microservices architecture](../assets/images/microservices-architecture-with-nginx.webp) 37 | 38 | To define an [`ingress`](../references/compose-spec.md#ingress-required), we need a `port` (the environment will be listening for traffic on this port) and a `service` (the requests coming to the port will be forwarded to this service). In our case, we will first create an `nginx` service in the compose file, and use this service as our `ingress`. 39 | 40 | ### **Step 1: Creating an Nginx container** 41 | 42 | Within your `docker-compose.uffizzi.yml` file, add a new service (within the services directive), we’ll name it `nginx`. Our `nginx` service will use the [official Nginx image from Docker Hub](https://hub.docker.com/_/nginx). If you want, you can also build a custom image based on Nginx’s official image. If you’re following the example on GitHub, please know that we have used a custom image for the nginx service (named `loadbalancer`) built on the official Nginx image. 43 | 44 | ``` yaml 45 | nginx: 46 | image: nginx:alpine 47 | deploy: 48 | resources: 49 | limits: 50 | memory: 125M 51 | ``` 52 | 53 | ### **Step 2: Creating Nginx configuration file** 54 | 55 | Once you have the above service added, we will now configure routing rules for Nginx to forward requests to the `voting-app` service and `result-app` service. 56 | 57 | We will create a new configuration file called `nginx.conf` and define how Nginx should handle request routing. Please make sure this file is placed under a directory, and the total size of the directory is smaller than 1 MB compressed (the limit is not applicable if you’re using [Uffizzi CI](../references/uffizzi-ci.md)). If you’re having trouble configuring volumes, read our [troubleshooting guide](../troubleshooting/most-common-problems.md). 58 | 59 | There are 2 ways traffic will come into the example app: 60 | 61 | 1. Users interact with the voting-app service to cast their votes 62 | 2. Users interact with the result-app to see results 63 | 64 | We will, therefore, need to route requests from the `nginx` service to these two services. Our requirements for the `nginx` (`ingress`) service are: 65 | 66 | - Requests to the root of our app should take users to the `result-app` service, where they can see the votes that have been cast so far. 67 | 68 | - The `result-app` service should redirect users to the `vote-app` service, where they can cast their votes. 69 | 70 | - The `vote-app` service must respond to the redirect from `result-app` and allow users to cast their votes. 71 | 72 | Here is the `nginx.conf` file: 73 | 74 | ``` 75 | server { 76 | listen 8080; 77 | server_name localhost; 78 | location / { 79 | proxy_pass http://localhost:8088/; # result-app addr 80 | } 81 | location /vote/ { 82 | proxy_pass http://localhost:8888/; # voting-app addr 83 | } 84 | } 85 | ``` 86 | 87 | In the above `nginx.conf` file, we have defined Nginx to listen on port `8080`. The port you define here should not be in use by other services/containers. Requests received at the root (defined by `/`) will be sent from Nginx to the `result-app` service. Requests received at `/vote` will be sent to the `vote-app` service. This config file will allow the `nginx` container—when configured as `ingress` in the `docker-compose.uffizzi.yml`—to receive HTTPS traffic and forward HTTP to the defined upstream. 88 | 89 | ### **Step 3: Configuring the Nginx container** 90 | 91 | We’ll now further configure the Nginx container to mount this config file into the container. Make the following changes to the `nginx` service: 92 | 93 | ``` yaml 94 | nginx: 95 | image: nginx:alpine 96 | environment: 97 | VOTE_HOST: "localhost" 98 | VOTE_PORT: "8888" 99 | RESULT_HOST: "localhost" 100 | RESULT_PORT: "8088" 101 | volumes: ./nginx-uffizzi:/etc/nginx 102 | deploy: 103 | resources: 104 | limits: 105 | memory: 125M 106 | ``` 107 | 108 | Take note of the `volumes` section. Currently, Uffizzi does not support mounting single files from the host to the container. We, therefore, placed the `nginx.conf` file into a directory called `nginx-uffizzi` and mount this directory to `/etc/nginx` in the container. 109 | 110 | According to the official docs from Nginx, for NGINX Open Source, where the config needs to be mounted will depend on the package system used to install NGINX and the operating system. It is typically one of `/usr/local/nginx/conf`, `/etc/nginx`, or `/usr/local/etc/nginx`. The `nginx.conf` is a highly configurable file that you can configure according to the needs of your app. However, instead of replacing the default `nginx.conf` altogether, we often recommend adding your configuration file(s) in the `/etc/nginx/conf.d/` directory, which Nginx will apply as additional configuration to the default `nginx.conf`. See [Nginx documentation](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/) for details on how multiple configurations are applied. 111 | 112 | ### **Step 4: Adding nginx container as our entrypoint/ingress into the ephemeral environment** 113 | 114 | After fully configuring the nginx container, let’s add this as the ingress to receive traffic into Uffizzi ephemeral environments. At the top-level of your compose file, add the following: 115 | 116 | ``` yaml 117 | x-uffizzi: 118 | ingress: 119 | service: nginx 120 | port: 8080 121 | ``` 122 | 123 | Your compose should look like this after adding the above snippet: 124 | 125 | ``` yaml 126 | x-uffizzi: 127 | ingress: 128 | service: nginx 129 | port: 8080 130 | services: 131 | nginx: 132 | image: nginx:alpine 133 | volumes: ./nginx-uffizzi:/etc/nginx 134 | deploy: 135 | resources: 136 | limits: 137 | memory: 125M 138 | other-services: 139 | image: service-image 140 | ``` 141 | 142 | Voila! After making these changes, and opening a PR in your project, a new environment will spin up, receiving HTTPS traffic on the port you have defined (here `8080`). Adding a reverse proxy as ingress for your ephemeral environments is a really powerful way of bringing your microservices application to Uffizzi. Scenarios we discussed above, and more, can efficiently be solved by adding Nginx into your Uffizzi ephemeral environments. For more blogs on enhancing developer productivity with ephemeral environments, check out [our blog](https://www.uffizzi.com/blog). If you want ephemeral environments for your microservices, [get in touch with us](https://www.uffizzi.com/contact) and let us know how we can help! 143 | 144 |   145 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Uffizzi Overview 2 | 3 | ## What is Uffizzi? 4 | Uffizzi is a platform that enables teams to easily create and destroy on-demand cloud environments for development, QA, staging, and more. These "ephemeral environments" give teams a flexible way to scale their test infrastructure, while avoiding the bottleneck of a traditional shared test environment. With Uffizzi ephemeral environments, developers can test pre-release branches in clean, isolated environments that are not polluted by previous tests. Uffizzi ephemeral environments can also be used by product and sales teams to preview new features for clients and other stakeholders. 5 | 6 | Other common names for ephemeral environments are _preview environments_, _on-demand environments_, _scratch environments_, _environments-as-a-service (EaaS)_, _pull request environments_, and _continuous previews_. 7 | 8 | ## How it works 9 | 10 | When added to your git repository or continuous integration (CI) pipeline, Uffizzi works in the background each time a change is made to your code—for example, when a pull request (PR) or merge request (MR) is opened, closed, or updated. Additionally, you can create environments via the Uffizzi CLI from your local workstation, or by manually triggering a CI workflow. 11 | 12 | If initiated via PR, Uffizzi will post a comment to your PR issue with a secure _https_ link to your ephemeral environment. Or you can customize your workflows to send the URL to another service like Slack. In either case, your environment is continually refreshed when you push new commits, so anyone reviewing the environment will see the latest changes. Uffizzi also handles clean up, so your environments last only as long as you need them. 13 | 14 | 15 | 16 | ## Quicklinks 17 | | Topic | Description | 18 | |--------|---------------| 19 | | [Quickstart](quickstart.md) | How to install and get started with Uffizzi | 20 | | [Using Uffizzi](using-uffizzi.md) | Detailed integration guide that covers git and/or CI integration | 21 | | [CLI Reference](references/cli.md) | Command-line reference | 22 | | [Troubleshooting](troubleshooting/most-common-problems.md) | Most common problems and ways to solve them | -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | # Install the Uffizzi CLI 2 | 3 | This guide describes how to install the command-line interface (CLI) tool [`uffizzi`](https://github.com/UffizziCloud/uffizzi_cli), which will allow you to create and manage ephemeral environments on Uffizzi Cloud. If you're self-hosting Uffizzi, you should instead follow the [self-hosting installation guide](https://github.com/UffizziCloud/uffizzi/blob/develop/INSTALL.md). 4 | 5 | ## Homebrew Tap 6 | 7 | For macOS or Linux users, you can install the Uffizzi CLI via the [Homebrew](https://brew.sh/) tap: 8 | 9 | ``` bash 10 | brew tap uffizzicloud/tap 11 | brew install uffizzicloud/tap/uffizzi 12 | ``` 13 | 14 | **Note**: Be sure to first run `brew tap` before running `brew install`. 15 | 16 | ## From the binrary releases 17 | The Uffizzi CLI is currently available as a binary for macOS and Linux. Windows users should use our official Docker container image, [available on Docker Hub](https://hub.docker.com/r/uffizzi/cli). 18 | 19 | === "Mac (AMD or ARM)" 20 | 21 | ``` bash 22 | curl -L -o uffizzi "https://github.com/UffizziCloud/uffizzi_cli/releases/latest/download/uffizzi-darwin" && sudo install -c -m 0755 uffizzi /usr/local/bin && rm -f uffizzi 23 | ``` 24 | 25 | === "Linux (AMD or ARM)" 26 | 27 | ``` bash 28 | curl -L -o uffizzi "https://github.com/UffizziCloud/uffizzi_cli/releases/latest/download/uffizzi-linux" && sudo install -c -m 0755 uffizzi /usr/local/bin && rm -f uffizzi 29 | ``` 30 | 31 | === "Windows / Docker" 32 | 33 | ``` bash 34 | docker run --interactive --rm --tty --entrypoint=sh uffizzi/cli 35 | ``` 36 | 37 | Alternatively, you can download binaries directly from the [GitHub Releases](https://github.com/UffizziCloud/uffizzi_cli/releases) page, then add the location to your `PATH`. 38 | 39 | ## Configure the CLI 40 | 41 | Once you've downloaded and installed the Uffizzi CLI, run `uffizzi config` to set the Uffizzi API server you want to use. Accept the default value `app.uffizzi.com` (Uffizzi Cloud): 42 | 43 | ``` bash 44 | $ uffizzi config 45 | ... 46 | Server: (app.uffizzi.com) 47 | ``` 48 | 49 | 50 | ## Login 51 | 52 | Login to Uffizzi Cloud or your installation of Uffizzi. 53 | 54 | ### Via GitHub or GitLab OAuth 55 | 56 | Once you've configured the Ufizzi CLI, you can login with your GitHub or GitLab credentials via `uffizzi login`. This command will open a browser window to https://app.uffizzi.com where you can sign up for a new account or sign in to an existing account. 57 | 58 | ``` bash 59 | uffizzi login 60 | ``` 61 | 62 | Once you're logged in, return to the CLI. You'll need to select which GitHub/GitLab account you want to use as the default account context, for example, if you have both a personal and organizational account. You can change this setting later with the [`uffizzi config`](references/cli.md#config) command. 63 | 64 | ``` bash 65 | $ uffizzi login 66 | Select an account: (Press ↑/↓ arrow to move and Enter to select) 67 | ‣ Acme Corp 68 | jdoe 69 | ``` 70 | 71 | For more information on Uffizzi's account model, see [Teams and Accounts on Uffizzi Cloud](topics/teams-and-accounts.md) and [Role-based Access Control](topics/rbac.md). 72 | 73 | ### Via Email/Password 74 | 75 | If you have an email and password login for Uffizzi, you can login via: 76 | 77 | ``` 78 | uffizzi login --email --username --server 79 | ``` 80 | 81 | ### Via Environment Variables 82 | 83 | Alternatively, for email/password accounts (i.e. not GitHub or GitLab OAuth), if you set environment varialbes `UFFIZZI_USER_EMAIL` and `UFFIZZI_USER_PASSWORD`, Uffizzi will log you in automatically when you run `uffizzi login`. 84 | 85 | ## Create a new project 86 | 87 | In Uffizzi, every environment must belong to a project. If this is your first time setting up Uffizzi, select **Create a new project**. Then enter a project name, slug, description. 88 | 89 | ``` bash 90 | $ uffizzi login 91 | ... 92 | > Create a new project 93 | ``` -------------------------------------------------------------------------------- /docs/quickstart-uffizzi-ci.md: -------------------------------------------------------------------------------- 1 | # Configure Uffizzi CI 2 | 3 | Uffizzi CI is an integrated build service provided by Uffizzi Cloud. Every time you push a new commit to your repository, Uffizzi CI receives a webhook and builds your application from source. Choose this solution if you don't already have a CI platform or don't want to use your existing solution to build preview images. [Learn more >](references/uffizzi-ci.md) 4 | 5 | ## Example Usage 6 | 7 | ### **1. Fork the `quickstart-uffizzi-ci` repository** 8 | Fork the [`quickstart-uffizzi-ci`](https://github.com/UffizziCloud/quickstart-uffizzi-ci) repository on GitHub. Be sure to uncheck the option **Copy the `main` branch only**. This ensures that the `try-uffizzi` branch will be included in your fork. 9 | 10 |
Click to expand 11 | 12 |
13 | 14 | #### What's in this repository? 15 | This repository includes a sample voting application that consists of five microservies. Also included in the repository is a Docker Compose template ([`docker-compose.uffizzi.yml`](https://github.com/UffizziCloud/quickstart-uffizzi-ci/blob/main/docker-compose.uffizzi.yml)) that describes the application stack and includes information required by Uffizzi. 16 | 17 | At a minimum, this file must include the following object definitions: 18 | 19 | 1. **[`services`](references/compose-spec.md#services)** - The container service(s) that make up your application. See [Docker Compose for Uffizzi](references/compose-spec.md) for supported keywords. 20 | 2. **[`x-uffizzi`](references/compose-spec.md#x-uffizzi-extension-configuration-reference)** - This is a custom extension field required by Uffizzi. 21 | 22 | a. [`ingress`](references/compose-spec.md#ingress-required) - Tells Uffizzi which of your `services` should receive incoming _https_ traffic 23 | b. [`continuous_previews`](references/compose-spec.md#continuous_previews) - Required by Uffizzi CI. Set the following values to `true`: 24 | 25 | - `deploy_preview_when_pull_request_is_opened: true` 26 | - `delete_preview_when_pull_request_is_closed: true` 27 | - `share_to_github: true` - Toggles commenting on GitHub pull request issues 28 | 29 | Your Docker Compose template must be committed to the branch that you merge _into_, i.e. your target base branch (typically this is your default branch). It is recommended to commit your compose file to the root directory, although this is not required. Note that all paths specified in your `docker-compose.uffizzi.yml` file should be relative to this file location. 30 | 31 | !!! Note 32 | See the [Docker Compose for Uffizzi reference guide](references/compose-spec.md) for a comprehensive list of supported keywords. 33 | 34 | ### **2. Create a project at uffizzi.com** 35 | 36 | If you haven't already done so, [create a Uffizzi Cloud account](https://app.uffizzi.com/sign_up). Once logged in, follow these steps to create project: 37 | 38 | 1. Select **New project** > **Uffizzi CI** > **Configure GitHub** 39 | 2. Install Uffizzi Cloud on your GitHub account 40 | 3. Install & Authorize the Uffizzi GitHub App your repository 41 | 4. Select **Set up project** for your desired repository 42 | 5. Add your `docker-compose.uffizzi.yml` file in **Project** > **Settings** > **Compose**. Be sure to choose the branch that you merge into, i.e. your target base branch. 43 | 6. Save and validate your compose; resolve any errors 44 | 7. Check your configuration with a test deployment 45 | 46 |
Click to expand (Screenshots) 47 |

1. Select New project > Uffizzi CI > Configure GitHub

48 | 49 |

2. Install Uffizzi Cloud on your GitHub account

50 | 51 |

3. Install & Authorize the Uffizzi GitHub App your repository

52 | 53 |

4. Select Set up project for the repository you just forked

54 | 55 |

5. Add your `docker-compose.uffizzi.yml` file in Project > Settings > Compose. Be sure to choose the branch that you merge into, i.e. your target base branch.

56 | 57 |

6. Save and validate your compose; resolve any errors

58 | 59 |

7. Check your configuration with a test deployment

60 | 61 |
62 | 63 | ### **3. Open a pull request for `try-uffizzi` branch against `main` in your fork** 64 | 65 | Be sure that you're opening a PR on the branches of _your fork_ (i.e. `your-account/main` ← `your-account/try-uffizzi`). If you try to open a PR for `UffizziCloud/main` ← `your-account/try-uffizzi`, a preview will not run in this example. 66 | 67 | That's it! This will kick off Uffizzi CI and post the Preview Environment URL as a comment to your PR issue. 68 | -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart Guide 2 | 3 | This guide covers how you can quickly get started using Uffizi to create virtual clusters. If you want to create Docker Compose-based environments instead, start with [this guide](docker-compose-environment.md). 4 | 5 | !!! Important 6 | Uffizzi virtual clusters are currently in beta. Our team is actively working to improve reliability and developer experience. Please report any bugs to bugs@uffizzi.com 7 | 8 | ## Prerequisites 9 | 10 | The following prerequisites are required for this guide: 11 | 12 | 1. A GitHub or GitLab account for creating a Uffizzi Cloud login 13 | 2. Installing and configuring the Uffizzi client 14 | 3. Deciding which continuous integration tool to configure, if any 15 | 16 | ## Install Uffizzi 17 | 18 | Download a binary release of the Uffizzi client from the [official release page](https://github.com/UffizziCloud/uffizzi_cli/releases). 19 | 20 | For more details, see the [installation guide](install.md). 21 | 22 | ## Create an account 23 | 24 | For this quickstart guide, we'll be creating an account on Uffizzi Cloud using your GitHub or GitLab login. The following command will provide you with a link to sign up via a browser. If you've already created an account at [uffizzi.com](https://uffizzi.com), this command will let you login to your existing account: 25 | 26 | ``` bash 27 | uffizzi login 28 | ``` 29 | 30 | !!! Note 31 | If you'd rather have an email/password based login on Uffizzi Cloud, [submit a request](mailto:accounts@uffizzi.com). 32 | If you're self-hosting Uffizzi, you should follow the [self-hosting guide](https://github.com/UffizziCloud/uffizzi/blob/develop/INSTALL.md) to create an account. 33 | 34 | ### Account setup 35 | 36 | 37 | 1. **Select an account** - In this step, you'll select your default account context. You can change this setting later with the [`uffizzi config`](references/cli.md#config) command. 38 | 39 | ``` 40 | $ uffizzi login 41 | Select an account: (Press ↑/↓ arrow to move and Enter to select) 42 | ‣ Acme Corp 43 | jdoe 44 | ``` 45 | !!! Note 46 | If you signed up with GitHub or GitLab, you'll see your personal account and any organizations or groups you belong to. Choose your organization/group account if you want to create ephemeral environments for your team applications. Otherwise, you can select your personal account to create clusters for personal projects. Note that Personal and Team accounts are billed separately. [Learn more >](topics/teams-and-accounts.md) 47 | 48 | 2. **Create a new project** - Select **Create a new project**. Enter a project name as "quickstart" or similar, then confirm the project slug. For project description, enter "Quickstart guide" or just leave it blank. 49 | 50 | ## Create a virtual cluster 51 | 52 | Let's create a [virtual Kubernetes cluster](topics/virtual-clusters.md) to which we'll apply manifests in the next steps. 53 | 54 | In the command below, replace `~/.kube/config` with the path to your kubeconfig file, if different. Uffizzi will merge with an existing kubeconfig at the location you specify. If you don't have a kubeconfig file, you can omit this option and Uffizzi will create a new kubeconfig file at `~/.kube/config`. 55 | 56 | ``` bash 57 | uffizzi cluster create --name quickstart --kubeconfig ~/.kube/config --update-current-context 58 | ``` 59 | 60 | The last option `--update-current-context` is equivalent to `kubectl config use-context`. It tells Uffizzi to set the default cluster context to the one that was just created. 61 | 62 | To verify that the cluster was successfully created, run: 63 | 64 | ``` bash 65 | uffizzi cluster list 66 | ``` 67 | 68 | ## Download an example application 69 | 70 | We'll be using an [example application](https://github.com/UffizziCloud/quickstart-k8s) to deploy onto our cluster. The following GitHub repository includes code for the applicaiton, along with Kubernetes manifests that describe its configuration. 71 | 72 | Clone the repository, then change to its directory: 73 | 74 | ``` bash 75 | git clone https://github.com/UffizziCloud/quickstart-k8s.git && \ 76 | cd quickstart-k8s 77 | ``` 78 | 79 | ## Apply the manifests to your cluster 80 | 81 | From the `quickstart-k8s/` directory, run the following `kubectl` command to apply the manifests from the `manifests/` directory to your cluster: 82 | 83 | ``` bash 84 | kubectl apply --kustomize . 85 | ``` 86 | 87 | The above will create deployments, services, and ingresses for `vote` and `result` applications. The hostnames on the ingresses are assigned dynamically so that users don't have to create their own and spend time sorting out possible hostname conflict issues. 88 | 89 | If you query your created ingress with `kubectl get ingress -A`, you should see something like the following: 90 | ``` 91 | NAME CLASS HOSTS ADDRESS PORTS AGE 92 | result uffizzi result-default-quickstart-cluster-320.uclusters.app.uffizzi.com 80, 443 14m 93 | vote uffizzi vote-default-quickstart-cluster-320.uclusters.app.uffizzi.com 80, 443 14m 94 | ``` 95 | 96 | ## Understanding Ingress on Uffizzi 97 | 98 | There are two ingress options on Uffizzi: default and custom. 99 | 100 | ### Default IngressClass `uffizzi` 101 | 102 | The default IngressClass for any ingress created in a virtual cluster is `uffizzi`. The hostnames will be overriden to the format below : 103 | 104 | ``` 105 | https://---.uclusters.app.uffizzi.com 106 | ``` 107 | 108 | This allows users to quickly start testing their serivces and routing traffic from the outside world without having to configure hostnames manually or provisioning their own Ingress controller. Alternatively, you can define a custom IngressClass, as described below. 109 | 110 | ### Custom IngressClass 111 | 112 | You can bring your own IngressClass, and install the necessary controller on your virtual cluster. Custom IngressClasses on Uffizzi virtual clusters are configured just like they are for a standard Kubernetes cluster. 113 | 114 | Follow the official kubernetes documentation for understanding what an [IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) is and how you can back it up by deploying your own [Ingress controller of choice](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/). 115 | 116 | ## Verify everything works 117 | 118 | You can verify that everything is working by opening both the ingress URLs in your browser. You can vote for cats or dogs from the vote service, then see the voting results in the result service. 119 | 120 | ## Clean up 121 | 122 | Once your done with this environment, you can clean everything up—including all Kubernetes resources and data—by deleting the cluster: 123 | 124 | ``` 125 | uffizzi cluster delete quickstart --delete-config 126 | ``` 127 | 128 | The `--delete-config` flag tells Uffizzi to delete this cluster, user, and context for your kubeconfig file. 129 | 130 | ## What's next? 131 | 132 | See advanced usage examples, like how to add Uffizzi to a continuous integration (CI) pipeline like GitHub Actions or GitLab CI, so you can create ephemeral environments on every pull request or merge request. 133 | 134 | [Using Uffizzi →](using-uffizzi.md){ .md-button .md-button--primary } 135 | 136 |   137 | -------------------------------------------------------------------------------- /docs/references/example-compose.md: -------------------------------------------------------------------------------- 1 | # Example Docker Compose files for Uffizzi 2 | 3 | ## **Monorepo example (using Uffizzi CI)** 4 | In this example, Uffizzi CI builds multiple serviecs that are all co-located in a single repository (i.e., a "monorepo") 5 | 6 | See the source code for this example here: https://github.com/UffizziCloud/example-voting-app-monorepo 7 | 8 | ```yaml title="docker-compose.uffizzi.monorepo.yml" 9 | # Uffizzi extension 10 | x-uffizzi: 11 | ingress: 12 | service: loadbalancer 13 | port: 8080 14 | continuous_preview: 15 | deploy_preview_when_pull_request_is_opened: true 16 | delete_preview_when_pull_request_is_closed: true 17 | share_to_github: true 18 | 19 | # Vote applicaiton 20 | services: 21 | redis: 22 | image: redis:latest 23 | 24 | postgres: 25 | image: postgres:9.6 26 | secrets: 27 | - pg_user 28 | - pg_password 29 | 30 | worker: 31 | build: ./worker # Assumes Dockerfile exists in this repo 32 | deploy: 33 | resources: 34 | limits: 35 | memory: 250M 36 | 37 | result: 38 | build: ./result 39 | context: Dockerfile # Or you can specify an alternate monorepo 40 | environment: 41 | PORT: 8088 42 | 43 | vote: 44 | build: ./vote 45 | deploy: 46 | resources: 47 | limits: 48 | memory: 250M 49 | environment: 50 | PORT: 8888 51 | 52 | loadbalancer: 53 | image: nginx:latest 54 | configs: 55 | - source: nginx-vote-conf 56 | target: /etc/nginx/conf.d/vote.conf 57 | 58 | # Loadbalancer configuration 59 | configs: 60 | nginx-vote-conf: 61 | file: ./vote.conf 62 | 63 | # Postgres credentials 64 | secrets: 65 | pg_user: 66 | external: true # indicates value is external to this repository 67 | name: "POSTGRES_USER" # i.e., value should be added in the Uffizzi Dashboard 68 | pg_password: 69 | external: true # indicates value is external to this repository 70 | name: "POSTGRES_PASSWORD" # i.e., value should be added in the Uffizzi Dashboard 71 | ``` 72 | 73 | ## **Polyrepo example (using Uffizzi CI)** 74 | In this example, Uffizzi CI builds services from source that are stored in different repositories (i.e. a "polyrepo"). 75 | 76 | See the source code for this example here: https://github.com/UffizziCloud/example-voting-worker/blob/main/docker-compose.uffizzi.yml 77 | 78 | ``` yaml title="docker-compose.uffizzi.2.yml" 79 | # Uffizzi extension 80 | x-uffizzi: 81 | ingress: # required 82 | service: loadbalancer 83 | port: 8080 84 | continuous_preview: 85 | deploy_preview_when_pull_request_is_opened: true 86 | delete_preview_when_pull_request_is_closed: true 87 | share_to_github: true 88 | # Vote applicaiton 89 | services: 90 | redis: 91 | image: redis:latest # Defaults registry is hub.docker.com 92 | postgres: 93 | image: postgres:9.6 # Defaults registry is hub.docker.com 94 | secrets: 95 | - pg_user 96 | - pg_password 97 | worker: 98 | build: . # defaults to ./Dockerfile 99 | deploy: 100 | resources: 101 | limits: 102 | memory: 250M 103 | result: 104 | build: 105 | context: https://github.com/UffizziCloud/example-voting-result#main 106 | dockerfile: Dockerfile 107 | environment: 108 | PORT: 8088 109 | vote: 110 | build: 111 | context: https://github.com/UffizziCloud/example-voting-vote # defaults to "Default branch" as set in GitHub (usually main/master) 112 | dockerfile: Dockerfile 113 | x-uffizzi-continuous-preview: 114 | deploy_preview_when_pull_request_is_opened: false 115 | deploy: 116 | resources: 117 | limits: 118 | memory: 250M 119 | environment: 120 | PORT: 8888 121 | loadbalancer: 122 | image: nginx:latest 123 | configs: 124 | - source: nginx-vote-conf 125 | target: /etc/nginx/conf.d/vote.conf 126 | # Loadbalancer configuration 127 | configs: 128 | nginx-vote-conf: 129 | file: ./vote.conf 130 | # Postgres credentials 131 | secrets: 132 | pg_user: 133 | external: true # indicates value is external to this repository 134 | name: "POSTGRES_USER" # i.e., value should be added in the Uffizzi Dashboard 135 | pg_password: 136 | external: true # indicates value is external to this repository 137 | name: "POSTGRES_PASSWORD" # i.e., value should be added in the Uffizzi Dashboard 138 | ``` 139 | 140 | ## Expose multiple routes in an ephemeral environment 141 | 142 | Some applications may want to expose different services at different routes, for example, `/` and `/console`. To do this, we can use `nginx` to map requests for specific ports to their target containers. We'll first add an `nginx` service to our Docker Compose file, then define the routes in an `nginx.conf` file. 143 | 144 | ```yaml title="docker-compose.uffizzi.3.yml" 145 | x-uffizzi: 146 | ingress: 147 | service: nginx 148 | port: 8081 149 | continuous_previews: 150 | deploy_preview_when_pull_request_is_opened: true 151 | delete_preview_when_pull_request_is_closed: true 152 | share_to_github: true 153 | 154 | services: 155 | nginx: 156 | image: nginx:alpine 157 | restart: unless-stopped 158 | ports: 159 | - "8081:8081" 160 | volumes: 161 | - ./uffizzi/nginx:/etc/nginx/conf.d/ 162 | 163 | app: 164 | depends_on: 165 | - "postgres" 166 | build: 167 | context: ./ 168 | dockerfile: ./Dockerfile 169 | ports: 170 | - 3001:3001 171 | 172 | postgres: 173 | image: postgres:14-alpine 174 | user: postgres 175 | environment: 176 | POSTGRES_USER: "postgres" 177 | POSTGRES_PASSWORD: "postgres" # See https://docs.uffizzi.com/guides/secrets/#add-secrets-element-to-your-docker-compose-template 178 | deploy: 179 | resources: 180 | limits: 181 | memory: 500M 182 | ``` 183 | 184 |   185 | 186 | Now we will create a new file in our repository `/uffizzi/nginx/nginx.conf` that defines how our paths will be exposed. By default the official `nginx:latest` base image we used in our Docker Compose file will include all `/etc/nginx/conf.d/*.conf` files. 187 | 188 | Now we will create a new file in our repository `/uffizzi/nginx/nginx.conf` that defines how our paths will be exposed. 189 | 190 | ```json title="nginx.conf" 191 | 192 | http { 193 | server { 194 | listen 8081; 195 | 196 | location / { 197 | proxy_pass http://localhost:3001; 198 | } 199 | 200 | location /console/ { 201 | proxy_pass http://localhost:3002; 202 | } 203 | } 204 | } 205 | 206 | ``` 207 | 208 | 209 | -------------------------------------------------------------------------------- /docs/references/uffizzi-ci.md: -------------------------------------------------------------------------------- 1 | # Uffizzi CI 2 | !!! Note 3 | If you use GitHub Actions, GitLab CI, or another CI provider, you do not need to use Uffizzi CI. 4 | 5 | ## What is Uffizzi CI? 6 | Uffizzi CI is an integrated build and deployment service provided by Uffizzi Cloud free of charge. Choose this solution if you don't already have a CI platform or don't want to use your existing solution to build preview images. 7 | 8 | Every time you push a new commit to your repository, Uffizzi CI receives a webhook and builds your application from source. This ensures that the latest changes are always included in your previews. To use Uffizzi CI, your code must be stored in a GitHub repository. 9 | 10 | ## Setting up Uffizzi CI 11 | To set up Uffizzi CI, you'll first need to create a project in the Uffizzi Dashboard, then install and authorize the Uffizzi GitHub App. Once you've done that, you'll connect a [Compose file](../references/compose-spec.md) in your project settings. 12 | 13 | ### **1. Create a Uffizzi CI project** 14 | 15 | If you haven't already done so, create a Uffizzi CI project. Login to the [Uffizzi Dashboard](https://app.uffizzi.com/sign_in), then navigate to **Account** > **Projects**. Select **New project** > **Uffizzi CI** > **Configure GitHub** 16 |
Click to expand (Screenshots) 17 | 18 |
19 | 20 | ### **2. Install & Authorize the Uffizzi GitHub App** 21 | After selecting **Configure GitHub**, you will be redirected to a GitHub login page to install and authorize the Uffizzi Cloud [GitHub App](https://docs.github.com/en/developers/apps/getting-started-with-apps/about-apps). If you have more than one GitHub account, be sure to install the GitHub App on the same account that you used to create your Uffizzi account. To install the Uffizzi Cloud GitHub App on an organizational account, you must have Owner permissions for your GitHub Organization. 22 | 23 |
Click to expand (Screenshots) 24 |

Install Uffizzi Cloud on your GitHub account

25 | 26 | 27 |
28 |
29 | 30 | Next, choose which repositories you wish to preview, then select **Install & Authorize**. Uffizzi requests only the minimum permissions it needs, which includes read access to your code and write access to pull request issues for posting comments. You can manage the GitHub App permissions from the **Developer Settings** page in GitHub. 31 | 32 | ### **3. Add a Compose file in project settings** 33 | 34 | After installing and authorizing the GitHub App, you will be redirected back to the Uffizzi Dashboard. From there you can select a repository to complete project set up. 35 | 36 | 1. Select **Set up project** for your desired repository 37 | 2. Add your [`docker-compose.uffizzi.yml`](../references/compose-spec.md) file in **Project** > **Settings** > **Compose file**. Be sure to choose the branch that you merge into, i.e. your target base branch. For example, if your team opens pull requests against `main`, select this branch. 38 | 3. Save and validate your Compose; resolve any errors 39 | 4. Check your configuration with a test deployment 40 | 41 |
Click to expand (Screenshots) 42 |

1. Select Set up project for the repository you just forked

43 | 44 |

2. Add your `docker-compose.uffizzi.yml` file in Project > Settings > Compose. Be sure to choose the branch that you merge into, i.e. your target base branch.

45 | 46 |

3. Save and validate your Compose; resolve any errors

47 | 48 |

4. Check your configuration with a test deployment

49 | 50 |
51 | 52 | 53 | ## How to use Uffizzi CI 54 | Once everything is configured on both GitHub and Uffizzi, you don't need to do anything special to get Uffizzi CI working. Open pull requests as you normally do. Uffizzi CI will work in the background to build your application every time a PR is opened, closed, reopened, or synchronized (i.e. new commits). Uffizzi will post a comment to your pull request issue with a link to your Preview Environment. You can also login to the Uffizzi Dashboard to see a list of all your previews and your application logs. 55 | 56 |
Click to expand (Screenshots) 57 |

Open a pull request on GitHub:

58 | 59 |
60 |

Uffizzi CI will post a comment to your pull request issue:

61 | 62 |
63 |

Log in to the Uffizzi Dashboard to see a list of Preview Environments and your application logs:

64 | 65 |
66 | 67 | ### When are previews triggered? 68 | 69 | Currently Uffizzi CI will only create previews for pull requests that target the branch you configure in the Uffizzi Dashboard (**Project** > **Settings** > **Compose file** > **Branch** > **Path to Compose**). 70 | 71 |
Click to expand (Screenshots) 72 |

Open a pull request on GitHub:

73 | 74 |
75 | 76 | For example, if you configure Uffizzi CI with a Compose file from your main branch, Uffizzi will apply the following logic: 77 | 78 | **Previews will be triggered for pull requests matching**: 79 | 80 | - `main` ← `{topic_branch}` 81 | 82 | **Previews _will not_ be triggered for pull requests matching**: 83 | 84 | - `{topic_branch}` ← `main` or 85 | - `{topic_branch}` ← `{topic_branch}` 86 | 87 | Note that this design may change in a future release of Uffizzi CI, such that all pull requests will be previewed for a given project. 88 | 89 | !!! Important 90 | If the Compose file in a base and head branches do not match for a given pull request, Uffizzi will use the Compose file in the head branch (i.e. the merging branch) as the preview configuration. 91 | 92 | For example, if a pull request is opened for `main` ← `my-feature` and the Compose files do not match, Uffizzi will use the Compose file from `my-feature`, 93 | 94 |   95 |   96 | -------------------------------------------------------------------------------- /docs/references/uffizzi-environment-variables.md: -------------------------------------------------------------------------------- 1 | # `UFFIZZI_URL` environment variable 2 | 3 | Each Uffizzi environment is assigned a unique, public URL that exists for the lifetime of the environment. This URL is accessible to all containers of your deployment via the environment variable `UFFIZZI_URL`. 4 | 5 | ### Uses 6 | 7 | It is often the case that components of an application need to know the endpoint of their host environment. For example, you may want your API to provide its own documentation using a tool like Swagger. Since Uffizzi URLs are dynamically generated when your application is deployed, you cannot preconfigure Swagger with the host URL. However, you can use `UFFIZZI_URL` to dynamically set the value of your API endpoint when it is generated by Uffizzi. 8 | -------------------------------------------------------------------------------- /docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | :root { 2 | 3 | /* Primary color shades */ 4 | --md-primary-fg-color: black; 5 | --md-primary-bg-color: hsla(0, 0%, 100%, 1); 6 | --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7); 7 | --md-primary-fg-color--dark: rgb(253, 216, 48); 8 | --md-text-link-color: hsla(231, 48%, 48%, 1); 9 | 10 | /* Accent color shades */ 11 | --md-accent-sh-color: rgb(67, 67, 67); 12 | --md-accent-fg-color: rgb(100, 100, 100); 13 | --md-accent-fg-color--transparent: hsla(189, 100%, 37%, 0.1); 14 | --md-accent-bg-color: hsla(0, 0%, 100%, 1); 15 | --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7); 16 | 17 | } 18 | 19 | :root>* { 20 | 21 | /* Code block color shades */ 22 | --md-code-bg-color: hsla(0, 0%, 96%, 1); 23 | --md-code-fg-color: hsla(200, 18%, 26%, 1); 24 | 25 | /* Footer */ 26 | --md-footer-bg-color: black; 27 | --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32); 28 | --md-footer-fg-color: hsla(0, 0%, 100%, 1); 29 | --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7); 30 | --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3); 31 | 32 | /* Link color */ 33 | --md-typeset-a-color: rgb(92, 127, 209); 34 | } 35 | 36 | /* Optionally remove the copy code button from code block */ 37 | .highlight.no-copy .md-clipboard { 38 | display: none; 39 | } 40 | 41 | 42 | /* H1 and H2 tags */ 43 | .md-typeset h1 { 44 | font-weight: bold; 45 | color: var(--md-primary-fg-color); 46 | } 47 | 48 | .md-typeset h2, 49 | .md-typeset h3 { 50 | font-weight: bold; 51 | color: var(--md-accent-sh-color); 52 | } 53 | 54 | /* Full-width tables */ 55 | .md-typeset__table { 56 | min-width: 100%; 57 | } 58 | 59 | .md-typeset table:not([class]) { 60 | display: table; 61 | } -------------------------------------------------------------------------------- /docs/topics/ci-cd-registry.md: -------------------------------------------------------------------------------- 1 | # Add Continuous Previews (CP) to your CI/CD 2 | 3 | This blog provides an example of how to integrate Uffizzi with an existing CI/CD solution to enable tag-initiated previews, also known as [Continuous Previews](continuous-previews.md). This guide walks you through setting up webhooks on the registry and using the Uffizzi image tagging convention `uffizzi_request_*` to trigger automated previews of new pull requests. 4 | 5 | We'll use GitLab CI/CD for builds and the Azure Container Registry (ACR) to store images, but the general method discussed here applies to any CI/CD and registry combination. For the application, we'll use [an example Python application that fetches and renders weather forecasts from NOAA](https://gitlab.com/adam.d.vollrath/noaafetch/). 6 | 7 | ## Azure Container Registry 8 | 9 | If you haven't yet, integrate your Azure Container Registry by following our [ACR integration documentation](../guides/container-registry-integrations.md#azure-container-registry-acr). You'll need the registry domain, Application (client) ID, and Secret or Password value for the next steps. 10 | 11 | ## GitLab CI/CD 12 | 13 | You can see my example [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) configuration file here: 14 | 15 | Most of this is very standard. The `before_script` logs into Azure as a [Service Principal](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals) before each Job. The `build` Job just builds a container image per a `Dockerfile` and pushes it to your ACR registry. 16 | 17 | To integrate with Azure, you'll need to [define some CI/CD variables in your GitLab Project](https://docs.gitlab.com/ee/ci/variables/#add-a-cicd-variable-to-a-project). I used these: 18 | 19 | - `AZURE_REGISTRY` - hostname of the Azure Container Registry, like `example.azurecr.io` 20 | - `AZURE_SP` - UUID of an Azure Application (client) ID 21 | - `AZURE_SP_PASSWORD` - secret value for the above Application 22 | 23 | It is **critical** that these variables not be "Protected" in GitLab because they must be used by Merge Request branches that are not Protected. 24 | 25 | Let's look at the last part of this file, the `Push merge_request` Job: 26 | 27 | ``` yaml title=".gitlab-ci.yml" hl_lines="10 11" 28 | Push merge_request: 29 | variables: 30 | GIT_STRATEGY: none 31 | stage: push 32 | only: 33 | # We want this job to be run on Merge Requests only. 34 | - merge_requests 35 | script: 36 | - docker pull $AZURE_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHA 37 | - docker tag $AZURE_REGISTRY/$CI_PROJECT_NAME:$CI_COMMIT_SHA $AZURE_REGISTRY/$CI_PROJECT_NAME:uffizzi_request_$CI_MERGE_REQUEST_IID 38 | - docker push $AZURE_REGISTRY/$CI_PROJECT_NAME:uffizzi_request_$CI_MERGE_REQUEST_IID 39 | ``` 40 | 41 | Notice the last two lines tag and push an image whose tag begins with `uffizzi_request_`. This is so Uffizzi can identify the new image is associated with a Merge Request. 42 | 43 | ## Uffizzi Compose File 44 | 45 | Next we'll add a `docker-compose.uffizzi.yml` file to our repository and configure Uffizzi to use it. At the moment, Uffizzi only reads Compose files from GitHub, so I've [cloned my example repository over there](https://gitlab.com/adam.d.vollrath/noaafetch). (Compose files on GitLab will be supported soon™.) Here's my example Compose file: 46 | 47 | This file tells Uffizzi where to fetch the container image, what memory resources it requires, which container receives traffic from the load balancer, and how to create new Previews when new images are pushed. You can read more in [Uffizzi's Compose Reference Guide](../references/compose-spec.md). 48 | 49 | ## Uffizzi Continuous Previews 50 | 51 | Lastly we'll configure Uffizzi to use our Compose file. Within your Uffizzi Project, select Specs on the left side and then click the yellow "New Compose" button. 52 | ![New Compose File](../assets/images/blog-1-new-compose.png) 53 | 54 | Select your GitHub repository and branch and then enter the filename of your Uffizzi Compose file. I used `docker-compose.uffizzi.yml`. 55 | ![Link Compose File](../assets/images/blog-1-link-compose.png) 56 | 57 | Validate and save this Compose spec. Now Uffizzi should be ready to deploy a new Preview whenever you open a GitLab Merge Request! 58 | 59 | ## Smoke Test 60 | 61 | Now let's tie it all together. Push a new commit on a new branch to your GitLab repository and then open a new Merge Request. GitLab's CI/CD will build a new image and push it to your Azure Container Registry. Uffizzi will recognize the new image and deploy it automatically. 62 | 63 | ![New Preview](../assets/images/blog-1-new-preview.png) 64 | -------------------------------------------------------------------------------- /docs/topics/continuous-previews.md: -------------------------------------------------------------------------------- 1 | # Continuous Previews: A Best Practice for Agile Teams 2 | Continuous Previews (CP) are an automation-enabled best practice that encourages cross-functional teams to continuously collaborate during the development process by providing feedback on features that are still in progress. With CP, git topic branches are previewed using on-demand test environments before they are merged into a downstream branch. 3 | 4 | CP helps solve both technical challenges and collaboration challenges. From a technical standpoint CP makes it easy to test pre-merge versions of your complete application with all of its services while at the same time working to eliminate barriers to team collaboration - particularly in a primarily remote work environment. 5 | 6 | This modern approach to agile enables teams to catch issues early, iterate quickly, and avoid the inefficiencies inherent in merging broken features or "dirty code". The following diagram illustrates how CP improves the standard agile development process: 7 | 8 | ![CP diagram](../assets/images/agile-with-cp.svg) 9 | 10 | **CP is not a replacement for Continuous Integration / Continuous Delivery (CI/CD). CP is designed to work in conjunction with CI/CD pipelines. You can think of CP as a preprocessing step that occurs before the merge, such that once you merge, your existing CI/CD pipeline takes over.** 11 | 12 | ## Previews vs. Standard Deployments 13 | 14 | | Previews | Standard Deployments | 15 | | --------------------------------------- | -------------------------- | 16 | | Ephemeral / purpose-driven lifecycle | Persistent / long-running | 17 | | Topic branches (features and bug fixes) | Production, Staging, QA | 18 | | Pre-merge | Post-merge | 19 | | Preview URL | Static URL | 20 | 21 | 22 | ## Previews vs. Continuous Previews 23 | 24 | | Previews | Continuous Previews | 25 | | --------------------------------------- | ------------------------------------------ | 26 | | Initiated and deleted ad hoc (e.g. docker-compose up/down) | Initiated and deleted via event webhooks (open/close PR, new/updated image tags) | 27 | | Typically for individual developer / local testing | Intended for sharing with team for feedback and approval | 28 | | | Team-focused System for Previewing | 29 | 30 | ## Benefits of Continuous Previews 31 | 32 | Teams incorporating Continuous Previews into their workflow often see the following benefits: 33 | 34 | * **Catch issues earlier in the Development Cycle where they are easier to Find and Fix** 35 | * **Improve Collaboration Across Dev and Product Teams to Iterate Faster** 36 | * **Reduce how often Test/QA environment breaks; ability to resolve breakage more quickly** 37 | * **Increase development velocity by reducing returned tickets** 38 | * **Reduce costs by replacing your static QA environment with dynamic preview environments** 39 | * **Eliminate the bottlenecks of shared Dev Environments - Deploy git branches without having to wait until they’re merged** 40 | * **Merge with confidence knowing a feature works as intended** 41 | * **Works with your existing CI/CD pipeline** 42 | 43 | A common bottleneck for software development teams is tracing the root cause of bugs in QA/Test. When multiple developers are pushing commits to a shared development branch, it’s difficult to know if a problem originated as a result of the integration step or if there was a problem with the feature itself. 44 | 45 | By testing the functionality of a topic branch before it’s merged into QA/Test, your team can be sure that any problems that occur after the merge are the result of an integration issue, not a functionality issue. That is, you can verify that a feature works as intended before it’s merged with everyone else’s code. 46 | 47 | By deploying your feature(s) to a publicly accessible endpoint - like the shareable preview URLs that Uffizzi provides - your teammates can view your work and provide timely feedback that reduces the number of returned tickets and ultimately improves development velocity. 48 | 49 | Continuous Previews can lead not only to time savings, but also cost savings. Teams employing an Agile + Continuous Previews strategy can often replace their single, static QA/Test environment with a dynamic set of test environments for each new topic branch. These dynamic test environments can share the same lifecycle as the topic branch itself—i.e., when a branch is created or deleted, a corresponding environment is stood up or torn down. This enables you to effectively "rent" your QA environment(s) - there's no reason to run QA environments in off hours, over the weekend, or during holidays - you can run these for a fraction of the time and have as many environments as you need for as long as you need them and no longer. 50 | 51 | To learn more see the [CP Manifesto](https://www.continuous-previews.org). 52 | 53 | -------------------------------------------------------------------------------- /docs/topics/docker-extension-partner.md: -------------------------------------------------------------------------------- 1 | # Announcing the Uffizzi Docker Desktop Extension: Test Your Compose Stack In An On-Demand Cloud Environment 2 | 3 | May 10th, 2022 – by [Josh Thurman](https://twitter.com/joshthurman19) 4 | 5 | Today we are thrilled to announce that Uffizzi is one of the first Extensions live on the Docker Desktop marketplace. Through the Docker Extensions Program we are making Uffizzi’s on-demand full-stack preview environments accessible within the Docker Desktop interface. 6 | 7 | This means Developers can streamline their workflows and reduce context switching to do their best work. Through Desktop and the Uffizzi Extension Developers now have the ability to manage their compose stack both locally and in an on-demand cloud environment. 8 | 9 | ![Marketplace](../assets/images/DD first page.png) 10 | 11 | Uffizzi extends Docker and Docker Desktop‘s capability by taking the popular Docker Compose configuration and applying it to on-demand cloud environments. This means that the millions of developers who use the compose stack for testing their application locally can now use that same configuration to define production-like test environments that are accessible at a secure, shareable URL. 12 | 13 | Teams using Uffizzi are transforming how they test new features with clean, production-like preview environments for every feature. The Continuous Previews capability that Uffizzi provides empowers teams to iterate faster and improve their overall development velocity. With our commitment to Docker Compose as a configuration, the Docker Extensions Partnership is a natural fit and is a big win for Developers. 14 | 15 | Series A Fintech [Tilled.com](https://tilled.com/)’s Head of DevOps and Quality Butch Mayhew noted regarding the Extension, “Uffizzi is super valuable to me, I don’t have to worry about the infrastructure, I just have to have a docker compose file and let Uffizzi do the hard work . . . it allows us to get feedback quickly in an automated fashion and also gives us a place to do some exploratory testing so as we get that merge to develop we’ll have high confidence in our releases.” 16 | 17 | The real power of Uffizzi’s on-demand environments is that they enable Developers and their teams to test new features in isolation and with all their dependencies. This eliminates the variables of commingled code being simultaneously introduced into what we would call a dirty environment. Introducing new features into an existing code base is hard enough, and when you can eliminate variables it’s a game-changer for how efficiently your team can release new features. 18 | 19 | Historically Docker Desktop has been an inner loop tool that organizes individual Developer workflows as they iterate. With the Uffizzi Extension, Desktop becomes a powerful outer loop tool that enables key stakeholders on your cross-functional team – whether it be peer review, QA, or product– to shift left and provide feedback on in-progress development. 20 | 21 | If you'd like to try Uffizzi you can start with a [Live Demo](https://uffizzi.com) on our main site or jump right into the [Docker Desktop Extensions Marketplace](https://www.docker.com/blog/ 22 | docker-extensions-discover-build-integrate-new-tools-into-docker-desktop). 23 | 24 | ## Relevant Resources 25 | 26 | -[Uffizzi Testimonials – How Series A Fintech tilled.com uses Uffizzi to achieve “high confidence releases”](https://www.youtube.com/watch?v=vPVBcq8qzj4&t=2s) 27 | 28 | -Download [Docker Desktop](https://www.docker.com/products/docker-desktop) 29 | 30 | -Github @UffizziCloud 31 | 32 | -Twitter [@Uffizzi_](https://twitter.com/Uffizzi_) 33 | 34 | ## Screenshots 35 | 36 | ![Marketplace](../assets/images/DD marketplace.png) 37 | ![DD Previews](../assets/images/DD-Previews.png) 38 | ![DD- deploying](../assets/images/DD deployed.png) 39 | ![DD- composespec](../assets/images/DDcomposespec.png) 40 | ![DD-logs](../assets/images/DDlogs.png) -------------------------------------------------------------------------------- /docs/topics/networking.md: -------------------------------------------------------------------------------- 1 | # Networking architecture 2 | 3 | All of a preview environment's containers are deployed within a single Kubernetes Pod. Containers within this Pod share their network namespaces—including their IP address. This means that containers within an environment can all reach each other on `localhost`. This is similar to using Docker's `host` network. 4 | 5 | This also means that containers must coordinate port usage, but this is no different from processes on a workstation or virtual machine. Be careful not to configure two or more containers to bind to the same TCP port. 6 | 7 | ## Load Balancing Incoming Traffic 8 | 9 | Every preview environment includes a load balancer that receives incoming HTTPS requests and routes them to the [HTTP port specified](https://docs.uffizzi.com/references/compose-spec/#ingress-required) for the container which receives incoming requests. Preview load balancers are set up and managed automatically, so you don't need to enable or configure them. The load balancer also handles HTTPS certificates for you; the certificate authority is trusted by all popular web browsers and devices. 10 | 11 | The load balancer will also set up an external IP address and DNS record, so you and your stakeholders can access it from anywhere via a public HTTPS URL. 12 | 13 | Separate preview environments do not share an internal network, so they may only communicate over the public Internet. 14 | 15 | ## Limitations 16 | 17 | - Only HTTP traffic is forwarded by the load balancer, and only to one container within each preview. If your application needs external traffic that is not HTTP, and/or needs to route external traffic to more than one container, please [let us know on Slack](https://join.slack.com/t/uffizzi/shared_invite/zt-ffr4o3x0-J~0yVT6qgFV~wmGm19Ux9A)! 18 | 19 | - Since all containers in a preview deployment exist within a Kubernetes Pod, they necessarily share the same lifecycle. By default, Uffizzi monitors the health of a Pod and will restart containers that fail or otherwise exit. While this design simplifies networking, scaling and other factors, it can lead to unexpected behavior when some of your containers are intended to persist while others terminate by design (such as a migration process). As a workaround, you may need to wrap your process in a command loop to keep it from terminiating. One-time jobs are on the Uffizzi roadmap to support this usecase. 20 | -------------------------------------------------------------------------------- /docs/topics/oidc.md: -------------------------------------------------------------------------------- 1 | # Authenticating via OpenID Connect 2 | 3 | _This article is relevant for [GitHub Actions](https://github.com/features/actions) users._ 4 | 5 | Using the official Uffizzi [preview action](https://github.com/marketplace/actions/preview-environments), GitHub Actions workflows authenticate with Uffizzi Cloud via OpenID Connect (OIDC) JSON Web Tokens (JWT). Every time a job runs, GitHub's OIDC Provider automatically generates an OIDC token, which is signed by GitHub to verify the workflow runner's identity. When this token is passed to the preview action, Uffizzi verifies the signature on the token to confirm that the request came from GitHub and the identity of the requester (i.e., the GitHub username). No other credentials are needed by Uffizzi to authenticate a request. This point is worth emphasizing: you do not need a password to authenticate with Uffizzi. In fact, **when the preview workflow runs for the first time, Uffizzi will automatically create an account from the metadata of the OIDC JWT**, so it's not even necessary to first create an account at _uffizzi.com_ before seeing your previews. -------------------------------------------------------------------------------- /docs/topics/rbac.md: -------------------------------------------------------------------------------- 1 | # Role-based access control 2 | 3 | Uffizzi provides role-based access to limit user privileges across your organization's account, projects and previews. The following list provides a summary Uffizzi RBAC roles and objects that may be restricted with RBAC. 4 | 5 | ## Accounts 6 | 7 | Accounts are associated with a customer billing account, typically the customer's company or organization. Accounts are at the top of the RBAC hierarchy. Currently, users may belong to only one organization (Support for membership in multiple organizational accounts is coming soon. As a temporary workaround, a user can be a member of multiple accounts by using different email logins.) 8 | 9 | ## Projects 10 | 11 | Projects fall within accounts and represent a development effort such as an application. Projects can be created and edited by [Owners](#owner) and [Developers](#developer). 12 | 13 | ## Team Members 14 | 15 | Members are individual users that are associated with an Account and have an assigned access role of [Owner](#owner), [Developer](#developer), or [View Only](#view-only). The Member who creates an Account is by default the Admin of that account. An account must always have at least one Admin. 16 | 17 | ## Single Sign-On (SSO) 18 | 19 | If a Member's Organization has enabled SSO for their account, then a Member must utilize the SSO function to log in to their account. Admins are still able to login in via email/password to administer SSO configuration. See [Single Sign-on](../guides/single-sign-on.md) for more details. 20 | 21 | ## Roles 22 | 23 | ### Owner 24 | Owners can do all and see all within an Account. Owners can view and edit every Project and previews. This is the highest level of permission for an account. Uniquely, Owners control the RBAC, Team creation/deletion, adding Team Members, Projects, integrations, settings and billing. An Account must have at least one Owner. 25 | 26 | ### Developer 27 | Developers can view, create, and edit Projects. They cannot edit Account-level settings like Billing, SSO, Team Members or integrations. A Developer can create Projects and be invited to Projects. 28 | 29 | ### View Only 30 | View Only users can see every Project and Owner Settings but cannot edit anything within Uffizzi. 31 | -------------------------------------------------------------------------------- /docs/topics/single-page-applications.md: -------------------------------------------------------------------------------- 1 | # Configure `API_BASE_URL` for React Apps and Other Single-Page Applications (SPA) 2 | 3 | In a typical single-page application (SPA) frontend + REST API backend example, the frontend service would have an `API_BASE_URL` or similar `ENV` `var` which points to the backend service. How would we set something like this up with Uffizzi’s preview environments? 4 | 5 | Each Uffizzi environment includes an environment variable [`UFFIZZI_URL`](../references/uffizzi-environment-variables.md) which is available to all containers in the environment. It’s value is the public endpoint of the environment, so if you just have a backend API deployed there, that’s what you’d need to provide to your frontend. Note that this URL is dynamically created when the ephemeral environment is created. 6 | -------------------------------------------------------------------------------- /docs/topics/teams-and-accounts.md: -------------------------------------------------------------------------------- 1 | # Teams and Accounts on Uffizzi Cloud 2 | 3 | The Uffizzi Team and Account model is tightly coupled with the GitHub and GitLab account models. For example... 4 | 5 | Uffizzi Cloud requires that you sign up for an account using either GitHub or GitLab OAuth. When you create a new account with Uffizzi, you are creating a personal account from your [GitHub Personal Account](https://docs.github.com/en/get-started/learning-about-github/types-of-github-accounts#personal-accounts) or [GitLab User Account](https://docs.gitlab.com/ee/user/profile/), depending on which provider you selected. Your Uffizzi personal account is always named after your personal GitHub/GitLab account. You cannot disassociate your Uffizzi personal account from your GitHub/GitLab personal account. If you sign in to Uffizzi with different GitHub/GitLab personal accounts, they will not be merged, i.e. you will have two separate Uffizzi personal accounts. 6 | 7 | A Uffizzi personal account may also be a Member of one or more Team accounts. 8 | 9 | When you create a Team on Uffizzi, you are creating it from a [GitHub Organizational Account](https://docs.github.com/en/get-started/learning-about-github/types-of-github-accounts#organization-accounts) or a [GitLab Group](https://docs.gitlab.com/ee/user/group/). Your Team is always named after your GitHub Organization or GitLab Group. You cannot disassociate your Team account from your GitHub Organization or GitLab Group. Projects created within the context of a Team account are only visible from your Team account. Similarly, projects within the context of your pesonal account, are only visible from your personal account, not your Team account. 10 | 11 | ## **`Accounts do not match` error** 12 | 13 | !!! Important 14 | You cannot attach GitHub Organization or GitLab Group credentials to a Uffizzi personal account. You must first create a Uffizzi Team for your GitHub Organization or GitLab Group, then configure credentials. Otherwise, you will see the error below. 15 | 16 |
Click to expand (Error message) 17 |

This error occurs when, for example, a personal account tries to configure credentials for a GitHub Organizational Account. You should first create a Uffizzi Team to conenct to a GitHub Organization / GitLab Group.

18 | 19 |
20 | 21 | ## **Create a Team** 22 | When you login to Uffizzi, you login to your personal account. You can switch to a Team account or create a new Team from the account dropdown. If you choose **Create team**, you will be asked to install the Uffizzi GitHub/GitLab App and select the repositories you want to configure. 23 | 24 |
Click to expand (Screenshots) 25 |

Account dropdown

26 | 27 |

Create a team

28 | 29 |

Choose an Organization to create a Team. If you choose a personal account in this step you will get an error in Uffizzi.

30 | 31 |

Select the repositories you want to configure with Uffizzi.

32 | 33 |
34 |   35 |   36 |   37 |   38 | 39 | -------------------------------------------------------------------------------- /docs/topics/virtual-clusters.md: -------------------------------------------------------------------------------- 1 | # What are Uffizzi virtual clusters? 2 | 3 | Similar to the concept of virtual machines, Uffizzi virtual clusters are virtualized instances of Kubernetes clusters running on top of a host cluster. Uffizzi virtual clusters provide all the same functionality of real Kubernetes clusters, while being more convenient and efficient. Virtual Kubernetes clusters are one of the configuration options for Uffizzi ephemeral environments (the other being [Docker Compose environents](../docker-compose-environment.md)). You can create virtual clusters from Helm charts, kustomizations, or regular Kubernetes manifests. Once created, you can manage Uffizzi virtual clusters with kubectl. 4 | 5 | You can let [Uffizzi Cloud](https://app.uffizzi.com) manage the host cluster for your team, or spin up virtual clusters on your own infrastructure by self-hosting Uffizzi. 6 | 7 | ## Easy provisioning 8 | Using the `uffizzi` CLI, you can create a cluster and update your kubeconfig in a single command, then use standard Kubernetes tools like `kubectl` to manage the cluster: 9 | 10 | ``` bash 11 | $ uffizzi cluster create -n my-cluster -k ~/.kube/config -m manifest.yaml 12 | ... 13 | $ kubectl get pods 14 | ``` 15 | 16 | Once you're done, clean everything up with a simple `uffizzi cluster delete` command. 17 | 18 | ## Bring your own tools 19 | Uffizzi virtual clusters work with the most popular Kubernetes management tools including `kubectl`, `kustomize`, and `helm`. 20 | 21 | ## Increased productivity 22 | With Uffizzi virtual clusters, developers no longer have to wait on cluster availability for testing, and if your team is self-hosting Uffizzi, operations teams only need to manage a single host cluster. 23 | 24 | ## Secure scaling 25 | Uffizzi virtual clusters provide secure multi-tenant Kubernetes out of the box, so workloads can safely and efficiently share underlying compute resources. This means every developer on your team can test their code in dedicated and isolated clusters whenever they need them. 26 | 27 | ## Cost-effective testing 28 | Whether you install Uffizzi on your own host cluster or are relying on Uffizzi Cloud, virtualization is the most cost-effective way to power your Kubernetes-based test environments. 29 | 30 | ## Getting started 31 | To get started with Uffizzi virtual clusters, follow the [quickstart guide](../quickstart.md). -------------------------------------------------------------------------------- /docs/topics/why-uffizzi.md: -------------------------------------------------------------------------------- 1 | Uffizzi helps alleviate two problems that commonly plague software development teams: 2 | 3 | 1. **Dirty code in your `main` branch**: Uffizzi provides Dev and QA teams with the ability to rapidly share and review new features before they're merged—catching bugs early and keeping them out of a team's `main` git branch. This capability also empowers a team to simplify their testing process by separating functional testing from integration testing - an individual developer's topic branch can be tested in isolation before merging it with the rest of the team's contributions. 4 | 5 | 2. **Limited Dev/QA environments**: Uffizzi eliminates problems associated with multiple developers sharing a single or limited number of test environments. With Uffizzi, previews are isolated (one developer's preview won't clobber another's) and ephemeral (they exist only as long as they are needed). New previews can be triggered when important events occur, like when a new PR is opened or a new image tag is created. Then previews environments are destroyed when the PR is closed or on a preset time-based deletion. If an on-demand environment is broken you can throw it away and create a new one without impacting your teammates. 6 | 7 | Uffizzi supports *configuration-as-code*. To configure Uffizzi, you provide a `docker-compose.uffizzi.yml` file that defines your application stack in Docker Compose syntax, along with a few extra parameters to tell Uffizzi when and how to deploy your previews. See the [Uffizzi Compose file reference](../references/compose-spec.md) for details or check out these [example Uffizzi Compose files](../references/example-compose.md). 8 | 9 | When Continuous Previews are configured, Uffizzi uses webhooks on your git repository or container registry to watch for changes to your application. When it detects a trigger, a new preview is deployed based on the policies you set within your Uffizzi Compose file. For each new preview, Uffizzi generates a secure, shareable URL, and when you push new commits/tag updates, the preview link is automatically updated. This allows you to avoid context switching by staying within a git workflow - you do not have to tell Uffizzi to deploy previews. 10 | 11 | ## Uffizzi-Managed Build vs. Bring Your Own Build Options 12 | Uffizzi supports deploying previews directly from your git repository or from a [container registry](../guides/container-registry-integrations.md). 13 | 14 | Users have the option for Uffizzi to build your application or you can [augment your existing CI/CD solution with a Continuous Previews (CP) capability](ci-cd-registry.md). 15 | 16 | If you are using your own CI/CD for the build, images tagged `uffizzi_request_<#>` can initiate new preview deployments. In addition to being compatible with custom build processes this allows for users on Gitlab, Bitbucket, or other Version Control Systems to immediately benefit from Uffizzi. 17 | 18 | ## What can I use Uffizzi for? 19 | 20 | - **Catch mistakes early** 21 | It's much easier to find and fix issues early in the development cycle than after an issue has been merged. Merge with confidence knowing a feature works as intended. 22 | 23 | - **Iterate quickly** 24 | Uffizzi helps improve collaboration across Dev and Product Teams to iterate faster. 25 | 26 | - **Accelerate release cycles** 27 | Uffizzi directly improves Lead Time, Cycle Time, Team Velocity, and Code Stability Key Performance Indicators (KPIs) 28 | 29 | - **Deconflict your shared Test/QA environment** 30 | You can eliminate the bottlenecks of a shared development environment since every developer on your team can have as many preview environments as they need. And because preview environments are isolated and ephemeral, you no longer have to worry that a new commit might break QA for the rest of the team. 31 | 32 | - **Trace root causes more easily** 33 | With Uffizzi, teams can test topic branches *before* they're merged. This means you can separate functional testing from integration testing, allowing you to merge with confidence knowing that the feature works as expected before it undergoes integration testing. 34 | 35 | - **Reduce costs** 36 | Uffizzi's preview environments can replace your static QA environment. Every preview exists in its own lightweight environment, which is destroyed when a PR is closed or after a certain number of hours. See [Uffizzi Compose file reference](../references/compose-spec.md) for configuration options. 37 | 38 | - **Augment your existing CI/CD pipeline with CP** 39 | Continuous Previews can be combined with your existing CI/CD solution 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/troubleshooting/debugging.md: -------------------------------------------------------------------------------- 1 | # **Debugging Uffizzi ephemeral environments** 2 | 3 | By [Shruti Chaturvedi](https://github.com/ShrutiC-git) 4 | 5 | Learn how to debug failures in your Uffizzi ephemeral environments. 6 | 7 | ## **Introduction** 8 | 9 | Before you start fixing an issue, you first need to know that something is failing and then identify where the failure is coming from. We published an article on [the most common reasons your ephemeral environments are faililing](most-common-problems.md). These errors can broadly be divided into three categories: 10 | 11 | - Errors with the `docker-compose.uffizzi.yml` (incorrect path to host-volume, missing ingress, etc). 12 | - Errors encountered while building the container (incorrect path to the Dockerfile, incorrect context, etc). 13 | - Errors encountered while running the application containers (OOM error, incorrect host-volume path, init-container exited causing the environment to become unserviceable, etc). 14 | 15 | In this article, we will take a look at where you can find and identify errors with your Uffizzi ephemeral environments. 16 | 17 | ## **Debugging environments built from Uffizzi CI** 18 | 19 | If you’re using Uffizzi CI to build and provision ephemeral environments, you’ll be able to access all the build logs and the container logs through the Uffizzi CI dashboard. Once you open a pull request in your project (make sure the target branch of the PR is also the branch that contains the docker-compose.uffizzi.yml you have added as the default configuration for your ephemeral environments), Uffizzi CI gets triggered to start building your application image from source, push it to a container registry, and spin the environment from this image. You can encounter errors due to misconfigurations in the docker-compose.uffizzi.yml. Alternatively, your application can throw an error while the application image is being built or while the application is running. 20 | 21 | ### Misconfigured `docker-compose.uffizzi.yml` 22 | As you connect your compose file to Uffizzi CI on the Uffizzi dashboard, it will be validated to make sure that the docker-compose is not misconfigured to run Uffizzi integration. If there are issues with validating your compose, a popup will appear on the same screen guiding you on what is wrong. If there is a missing directive (like ingress), or an incorrect path to your host volume, `docker-compose.uffizzi.yml` validation will throw an Invalid compose error. 23 | 24 | For example, if you do not specify an ingress in your `docker-compose.uffizzi.yml`, which is needed by Uffizzi to define an entrypoint into your environment, you’ll see the following on this screen: 25 | 26 | 27 | 28 | Please note that this step does not validate issues with application-level misconfigurations, for example, insufficient memory allocated to the container or an incorrect environment variable. 29 | 30 | Once you’ve added a valid compose file, you’ll be able to test it by clicking the Test Compose button on the Settings page to make sure that there are no application-level issues in the compose file. 31 | 32 | ### Build Errors 33 | If, for example, your Uffizzi is unable to locate your application Dockerfile given in the `docker-compose.uffizzi.yml`, Uffizzi will fail to build the application image. If there are other issues in your Dockerfile, for example, issues with conflicting dependencies, in this case too, building the image will fail, and hence, Uffizzi will fail to create/modify an ephemeral environment. In either case, you would want to check the build logs. 34 | 35 | To identify issues with building your application image, head over to the Uffzzi dashboard and select the project you’re debugging (you might have one or multiple projects listed on the dashboard). You will then see all currently active ephemeral environments for this project. If you are debugging a particular ephemeral environment for a specific PR, you can select that environment. Typically, the timestamp of when the environment was updated along with the Preview URL, which looks something like _https://pr-10-deployment-1234-your-application.app.uffizzi.com_, will help you identify if that environment corresponds to your PR. 36 | 37 | Once you select the environment you are debugging, you will see a list of all the containers in that project. If a container has failed (either while the image-building process or while running the container), you will see it marked failed on the Uffizzi UI. 38 | 39 | Selecting a container will take you to the container logs (these will be logs from the application container itself). We will look at checking the container logs in the next step. 40 | 41 | The vertical navbar on the left side lists a tab called Build Logs. Click this tab and you will then be able to look at the build logs for that particular container. The build logs will log the steps taken to build the application image from the Dockerfile you have specified in your `docker-compose.uffizzi.yml`. You could either look through the build logs to go through each step. Alternatively, you can also filter build logs for generic or application-specific keywords. 42 | 43 | 44 | 45 | For example, in the case where you have passed an incorrect path to Dockerfile in your docker-compose.uffizzi.yml, you’ll see something like this in your build logs: 46 | 47 | ``` 48 | Step #2: unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /workspace/build/ci/Dockerfile: no such file or directory 49 | Finished Step #2 50 | ERROR 51 | ERROR: build step 2 "******/cloud-builders/docker" failed: step exited with non-zero status: 1 52 | ``` 53 | 54 | Checking the build logs is a very helpful step in identifying issues with building your application container image. You can also view the logs post environment creation (in case the build passes successfully) for debugging purposes—if the environment is refreshed, the build step is retriggered, and hence the logs also change to correspond to the new build. It is important to note that the build logs will only be available for the container's you are building from the source. If a container pulls an image from a container registry, there will be no build logs for such a container. 55 | 56 | ### Application Errors 57 | 58 | Your application could have failed due to an error thrown by one or more of your containers. When you come onto the Uffizzi dashboard, select your, and select the ephemeral environment you’re testing, all the containers defined in your ephemeral environments will be listed. 59 | 60 | Selecting a container will list the execution logs for this container. Generic errors like [`OOM kill`](most-common-problems.md#1-container-killed-due-to-insufficient-memory-oom-kill) will mark the container as failed. You can visit the Troubleshooting guide on how to fix common errors with your Uffizzi ephemeral environments. In other cases, if your container failed and exited due to an application-specific error, you can check the container logs to figure out the root cause of the issue. Sometimes, the ephemeral environment might not work as it is supposed to despite all the containers passing successfully. For example, if the backend fails to connect to the database, the backend container might not be marked as failed, but the environment will not work as expected. In this case, I would benefit from checking container logs from both the backend container and my database container to figure out why the backend is unable to connect to the database. 61 | 62 | See below what the container logs on Uffizzi UI look like: 63 | 64 | 65 | 66 | If your container restarted or keeps restarting, you’ll also be able to look into the logs of the previous container and check why the container had to restart. 67 | 68 | ## **Debugging environments built using GitHub Actions (or other external CI)** 69 | If you have Uffizzi integrated into external CI, like GitHub Actions or GitLab CI, the external CI handles building and pushing the image, and thereafter, pulling it to create a new ephemeral environment. The external CI will also handle modifying and/or deleting the environment depending on the status of the PR. Therefore, you’ll need to check logs from your external CI to make sure the application image builds and is pushed to the registry successfully; your compose file is valid; the environment gets successfully created, updated, and/or deleted. For checking application/container logs, you will have to check these on Uffizzi UI. 70 | 71 | Usually, if the environment is not up while you are expecting it to be, this typically would suggest an issue either with the build failing or an invalid compose file. Either way, in case you are using an external CI, it is always a good idea to check logs from your external CI, and then head over to Uffizzi UI for further debugging. Check the section above on where to find application-level logs. 72 | 73 | ### Debugging Errors on GitHub Actions 74 | 75 | We’re looking at an example of debugging your Uffizzi ephemeral environments built through GitHub Actions. Once you open a PR after adding the GitHub Action workflow file in your default branch, a new GitHub Action to build and deploy your Uffizzi ephemeral environment will be triggered. Head over to the Actions tab in the repository, and you’ll see a new run triggered for your action. Similar to the Uffizzi CI, the branch name and the timestamp will give you an idea of the action corresponding to your change. 76 | 77 | After selecting a particular run, you’ll then see the status of each of the steps for this action. 78 | 79 | 80 | 81 | In the above image, we can see that all except one build job have passed. Clicking on the job that failed, I’ll be able to check all the steps of the job, and identify which step failed and for what reason. Once you update your PR with a fix for the error, a new run of the action will be triggered, and if passed successfully, all the steps will be marked green. You can then visit your ephemeral environment through the URL posted as a comment on your PR. In case the environment does not work as expected or throws an unexpected error, check the container logs on Uffizzi dashboard. 82 | 83 | ## **Next Steps** 84 | 85 | Once you find the root cause behind a failing ephemeral environment, the next step is fixing them. We identified the top places where misconfigurations occur and wrote a [troubleshooting guide](most-common-problems.md) to help projects easily get set up with Uffizzi. If you’d like to get more help, [reach out to us](https://www.uffizzi.com/contact) and let us know how we can help! 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/troubleshooting/file-or-directory-is-too-large.md: -------------------------------------------------------------------------------- 1 | # Error: File or Directory is Too Large 2 | 3 | By [Shruti Chaturvedi](https://github.com/ShrutiC-git) 4 | 5 | Are you trying to mount a host file and/or directory to your Uffizzi ephemeral environment built using external CI, and seeing an error that says the file or directory is too large? In this article, we’ll take a look at how you can solve this problem. 6 | 7 | ## Problem 8 | We often come across use cases where projects need to mount host files and directories to their Uffizzi ephemeral environments. This can be achieved through the [`volumes` directive](../references/compose-spec.md#volumes-1) within services in the docker-compose.uffizzi file (example below): 9 | 10 | ``` yaml 11 | services: 12 | proxy: 13 | image: nginx 14 | volumes: 15 | - ./nginx_conf:/etc/nginx 16 | 17 | volumes: 18 | share_db: 19 | ``` 20 | 21 | Uffizzi compresses the source file or directory to archive. If you’re using Uffizzi with an external CI, the size of this archive needs to be less than 1 MB, the currently supported limit (support for larger volumes is planned). If you mount a file or directory, which is larger than 1 MB compressed, you’ll see an error, **`File or Directory is Too Large`**. 22 | 23 | As a workaround, you can mount multiple volumes each up to 1 MB, Mouting multiple volumes, however, be onerous for cases where multiple files and/or directories need to be mounted, each coming to be larger than 1 MB compressed. 24 | 25 | The question is: how to mount larger files and/or directories on Uffizzi ephemeral environments built using an external CI in cases where mounting multiple volumes is cumbersome. Below are the steps of how you can achieve this effortlessly. 26 | 27 | ## Solution 28 | In this example, we are looking at how you can make larger files (compressed size over 1MB) available to your Uffizzi ephemeral environment built using GitHub Actions (GHA). The same procedure can be followed for other external CIs. 29 | 30 | The solution assumes that the file or directory you’re mounting is available in your git repo. Once the file is available in the git repo, you then download the zipped source (or clone the repo) into your container using the command directive. Depending upon your use case, you might have to export certain variables from your external CI and use these within `docker-compose.uffizzi.yml`. Step-by-step below: 31 | 32 | ### **Step 1: Export GHA Context Variables** 33 | This is an important step in the case where the file or directory to be mounted changes the behavior of the environment. The variables we export will make sure that the most recent changes in your repo are downloaded in the container. 34 | 35 | In your GHA workflow file, under the Render Compose File step in the render-compose-file job export the following variables: 36 | **github.actor** → represents the committer 37 | **github.event.repository.name** → represents the name of the repository (head repository, in case the environment was spun for a PR from a fork) 38 | **github.head_ref** → represents the branch within the repo for which the environment will be spun 39 | 40 | These [GitHub context](https://docs.github.com/en/actions/learn-github-actions/contexts#github-context) variables will make sure that the repository that is downloaded to the container—which includes the file or the directory that needs to be mounted—contains the most recent changes. 41 | 42 | The _render-compose-file_ step in your GHA workflow file should look like this: 43 | 44 | ``` yaml 45 | render-compose-file: 46 | name: Render Docker Compose File 47 | # Pass output of this workflow to another triggered by `workflow_run` event. 48 | runs-on: ubuntu-latest 49 | needs: 50 | - build-application 51 | outputs: 52 | compose-file-cache-key: ${{ steps.hash.outputs.hash }} 53 | steps: 54 | - name: Checkout git repo 55 | uses: actions/checkout@v3 56 | - name: Render Compose File 57 | run: | 58 | APP_IMAGE=${{ needs.build-application.outputs.tags }} 59 | export APP_IMAGE 60 | GHA_ACTOR=${{github.actor}} 61 | GHA_REPO=${{github.event.repository.name}} 62 | GHA_BRANCH=${{github.head_ref}} 63 | export GHA_ACTOR GHA_REPO GHA_BRANCH 64 | # Render simple template from environment variables. 65 | envsubst < ./uffizzi/docker-compose.uffizzi.yml > docker-compose.rendered.yml 66 | cat docker-compose.rendered.yml 67 | ``` 68 | 69 | You’ll need these variables only if you want the most recent changes reflected in your environment. If, however, your environment is not dependent on changes you make, these variables are not needed. 70 | 71 | ### **Step 2: Download the git repo in your container** 72 | You can now download the git repo in your container. Once you have access to the file/directory, you can then also move it to a custom location as if you were mounting a volume to a certain destination. 73 | 74 | In the following example, we will download the zipped source that contains the directories our container needs with the most recent changes using `wget` (make sure the utility is available in your container). In your `docker-compose.uffizzi.yml`, make the following changes in your container: 75 | 76 | ``` yaml 77 | app: 78 | image: my_app_image 79 | ports: 80 | - "3000:3000" 81 | entrypoint: ["/bin/bash"] 82 | command: 83 | - "-c" 84 | - "apt-get update && \ 85 | apt-get install wget -y && \ # install wget 86 | wget 'https://github.com/$GHA_ACTOR/$GHA_REPO/archive/refs/heads/$GHA_BRANCH.zip' && \ # download the most recent changes from the git repo 87 | unzip $GHA_BRANCH.zip -d . && \ # unzip at root 88 | rm -rf $GHA_BRANCH.zip # delete the zipped folder 89 | " 90 | ``` 91 | 92 | As your container comes up, these commands will be executed, and your git repo will be downloaded at the location you define in your container, and unzipping it will make your entire project available in the container. Alternatively, if your ephemeral environment is not dependent upon changes made to the file/directory you’re trying to mount, you can also simply clone the remote repository into the container at the location you want. 93 | 94 | This way the files and the directories you need will be made available to your application, and you will have easily passed the `File or Directory Too Large` error. In case this approach does not solve your problem, [reach out to us](https://www.uffizzi.com/contact) and let us know how we can help. 95 | 96 |   -------------------------------------------------------------------------------- /docs/troubleshooting/most-common-problems.md: -------------------------------------------------------------------------------- 1 | # **Troubleshooting Guide** 2 | 3 | By [Shruti Chaturvedi](https://github.com/ShrutiC-git) 4 | 5 | ## **Most common problems** 6 | 7 | Learn about the possible reasons your Uffizzi ephemeral environments might be failing and how you can fix them. 8 | 9 | ## Introduction 10 | 11 | You’ve now added Uffizzi integration into your project; you create a new PR, and you’re getting ready to access your ephemeral environment and get your feature reviewed. But, something seems to have failed — it could be the container-build step or perhaps an issue with insufficient memory. Some of these issues, like an out-of-memory (`OOM`) error, can be due to application-level misconfigurations in the docker-compose.uffizzi.yml file, while other issues can be due to misconfigurations in appropriately setting-up GitHub Actions (or alternatively Uffizzi CI) to build your application and provision ephemeral environments. 12 | 13 | This article will cover some of the top reasons your Uffizzi ephemeral environments might not be working and go through the process of fixing these issues so you can quickly get your ephemeral environments running efficiently. 14 | 15 | ## **1. Container killed due to insufficient memory (`OOM Kill`)** 16 | The most common reason Uffizzi ephemeral environments might not be working is an out-of-memory (`OOM`) error. This error occurs when a container does not have enough resources assigned to it. 17 | 18 | If no memory limit is set in the `docker-compose.uffizzi.yml`, by default, Uffizzi sets a 500 megabytes (`500M`) memory limit on each container, which may not be sufficient for certain memory-intensive applications. If insufficient memory is allocated to a container, the container will either exit with the `OOM` error or sometimes with an application-specific exit code indicating that the containerized application needs more memory. 19 | 20 | If you see your container exiting due to OOM Kill you can increase its memory by using the deploy.resources.limits key in your docker-compose.uffizzi.yml file. 21 | 22 | memory defaults to `500M`, but you can increase the memory using the following increments: `1000M`, `2000M`, and `4000M`. 23 | 24 | ``` yaml 25 | services: 26 | myservice: 27 | image: example.azurecr.io/example-service:latest 28 | deploy: 29 | resources: 30 | limits: 31 | memory: 500M 32 | ``` 33 | 34 | Uffizzi supports the following memory limits for a container `125M`, `250M`, `500M`, `1000M`, `2000M`, and `4000M`. Depending upon the memory usage of your application, you can set either of these limits on your containers. In case your application needs more memory, you can contact us [here](mailto:support@uffizzi.com). 35 | 36 | ## **2. Container dependency chain is not working** 37 | Uffizzi does not currently support [`depends_on`](https://docs.docker.com/compose/compose-file/#depends_on) within the `docker-compose.uffizzi.yml` to define container dependencies. In case your container needs to wait for other containers to start, you can use tools like [**dockerize**](https://github.com/jwilder/dockerize), [**wait4ports**](https://github.com/erikogan/wait4ports), or [**wait-for-it**](https://github.com/vishnubob/wait-for-it). [dockerize](https://github.com/jwilder/dockerize) supports waiting for services on a number of protocols: `file`, `TCP`, `HTTP`, `HTTPS`, and `Unix`. [wait-for-it](https://github.com/vishnubob/wait-for-it) and [wait4ports](https://github.com/erikogan/wait4ports) only support `TCP` sockets. To use [dockerize](https://github.com/jwilder/dockerize) and [wait4ports](https://github.com/erikogan/wait4ports), you can go through the installation steps to add these as dependencies in your application. [wait4ports](https://github.com/erikogan/wait4ports) on the other hand is a shell script, and you’ll only need the [`wait-for-it.sh`](https://github.com/vishnubob/wait-for-it/blob/master/wait-for-it.sh) script to use this tool. 38 | 39 | Depending upon the tool you’re using, once it is configured, it can be used with the [`entrypoint`](https://docs.uffizzi.com/references/compose-spec/#entrypoint) or [`command`](https://docs.uffizzi.com/references/compose-spec/#command) directives in the `docker-compose.uffizzi.yml`. Alternatively, you can also wrap the call to your application using the `ENTRYPOINT` or `CMD` directives in the application’s `Dockerfile`. 40 | 41 | For example, your backend application might need to wait for Postgres to be running before it starts. Here is how you can define that dependence in your `docker-compose.uffizzi.yml` using `dockerize`: 42 | 43 | ``` yaml 44 | entrypoint: ["dockerize", "-wait", "tcp://localhost:5432", "-timeout", "3600s"] 45 | ``` 46 | 47 | The `timeout` flag is optional. In case Postgres cannot be reached within the limits of the timeout, your application will exit with code `1`. 48 | 49 | This can also be defined using the [`command`](https://docs.uffizzi.com/references/compose-spec/#command) directive: 50 | 51 | ``` yaml 52 | command: ["dockerize", "-wait", "tcp://localhost:5432", "-timeout", "3600s"] 53 | ``` 54 | 55 | Using `wait4ports`: 56 | ``` yaml 57 | entrypoint: ["wait4ports", "tcp://localhost:5432"] 58 | ``` 59 | 60 | Using `wait-for-it` (make sure you have added the [`wait-for-it.sh`](https://github.com/vishnubob/wait-for-it/blob/master/wait-for-it.sh) script to your application’s runtime): 61 | 62 | ``` yaml 63 | entrypoint: ["./wait-for-it.sh tcp://localhost:5432"] 64 | ``` 65 | 66 | ## **3. Init container finishes and a previously working environment throws `Service Unavailable` error** 67 | 68 | Often if an application has init containers, the ephemeral environments will start throwing a `Service Unavailable` error as soon as the init container completes successfully and exits. This happens because all the containers in a given environment have the same life cycle. Therefore, when an init container completes its execution and exits, the other containers also exit and your ephemeral environment might throw a `503` error. 69 | 70 | To prevent your containers from exiting when the init containers complete execution, you’ll need to keep the init container running by providing it with an infinite process. There are a few of ways to do this: 71 | 72 | - Add an infinite loop at the end of the init-container script 73 | - Use `tail -f /dev/null`, or use `sleep infinity` 74 | - Adding any process that will keep the init container running will fix this issue 75 | 76 | ## **4. Volumes: file or directory is too large** 77 | 78 | When mounting host/non-empty [`volumes`](https://docs.uffizzi.com/references/compose-spec/#volumes_1), you might get an error saying that the file or the directory you’re mounting is too large. Currently, [Uffizzi support non-empty volumes for files and directories up to 1MB (compressed)](https://docs.uffizzi.com/references/compose-spec/?h=non+empty#volumes_1), although you can mount multiple volumes each up to 1M. 79 | 80 | If the size of the file or the compressed folder you’re mounting exceeds 1MB, you’ll get the error - `file or directory is too large` during the creation of your ephemeral environment. 81 | 82 | As a workaround, you can mount multiple non-empty volumes in your `docker-compose.uffizzi.yml`: 83 | 84 | ``` yaml 85 | services: 86 | app: 87 | image: myproject/app 88 | volumes: 89 | - ./frontend/public/svg:/frontend/public/svg 90 | - ./frontend/public/assets:/frontend/public/assets 91 | - ./frontend/src/app:./frontend/src/app 92 | ``` 93 | 94 | ## **5. Passing files as source path to non-empty volumes** 95 | 96 | You cannot directly pass the path to files as non-empty [`volumes`](https://docs.uffizzi.com/references/compose-spec/#volumes_1). The following way of mounting files will **fail** the deployment: 97 | ``` yaml 98 | services: 99 | app: 100 | image: nginx 101 | volumes: 102 | - ./nginx/nginx.conf:/etc/nginx/nginx.conf 103 | ``` 104 | 105 | 106 | If you want to mount a file(s) onto your container, you can place it in a directory and mount the directory. You can try the previous case in this way: 107 | ``` yaml 108 | services: 109 | app: 110 | image: nginx 111 | volumes: 112 | - ./nginx:/etc/nginx 113 | ``` 114 | 115 | If you are using Uffizzi CI, you can utilize the [`configs`](https://docs.uffizzi.com/references/compose-spec/#configs_1) directive in the `docker-compose.uffizzi.yml` file. The above, in Uffizzi CI, can be achieved in the following way: 116 | 117 | ``` yaml 118 | services: 119 | nginx: 120 | image: nginx 121 | configs: 122 | - source: nginx-conf 123 | target: /etc/nginx/nginx.conf 124 | configs: 125 | nginx-conf: 126 | file: ./nginx/nginx.conf 127 | ``` 128 | 129 | ## **6. Setting and accessing sensitive environment variables** 130 | If you are trying to set sensitive environment variables like access tokens, secret keys, etc, there are different ways to do this in the Uffizzi CI and external CI providers like GitHub Actions. 131 | 132 | ### Uffizzi CI 133 | Uffizzi CI supports the [`secrets`](https://docs.uffizzi.com/references/compose-spec/#secrets_1) directive in the `docker-compose.uffizzi.yml`. These secrets should be first added through the Uffizzi dashboard (check out [how to add secrets in the Uffizzi dashboard](https://docs.uffizzi.com/guides/secrets/#add-secrets-in-the-uffizzi-dashboard-appuffizzicom)) and then these can be accessed securely across all services in the stack. 134 | 135 | **Example** 136 | ``` yaml 137 | services: 138 | db: 139 | image: postgres:9.6 140 | secrets: 141 | - pg_user 142 | - pg_password 143 | 144 | secrets: 145 | pg_user: 146 | external: true 147 | name: "POSTGRES_USER" 148 | pg_password: 149 | external: true 150 | name: "POSTGRES_PASSWORD" 151 | ``` 152 | 153 | Make sure to set the `external` flag to true—it indicates that the [`secret`](https://docs.uffizzi.com/references/compose-spec/#secrets_1) object (name/value pair) is declared in the Uffizzi Dashboard (UI). 154 | 155 | ### External CI Providers 156 | If you are using external CI providers like GitHub actions, GitLab CI, etc, you cannot directly use the [`secrets`](https://docs.uffizzi.com/references/compose-spec/#secrets_1) directive. However, you can still use sensitive information in your application by storing it within your external CI provider and accessing it through the [`environment`](https://docs.uffizzi.com/references/compose-spec/#environment) directive in the `docker-compose.uffizzi.yml` file with variable substitution. 157 | 158 | **Example with GitHub Actions** 159 | Once you have added the secrets to your GitHub repository, these can be accessed in your GitHub Actions (GHA) workflow file. You can then export them and consequently, they will be available for use within your compose file. 160 | 161 | [After you have added your secret to your GitHub repository](https://docs.github.com/en/actions/security-guides/encrypted-secrets), add the following line to the _Render Compose File_ step in the _render-compose-file_ job: 162 | ``` yaml 163 | SOME_SECRET=${{secrets.SOME_SECRET}} 164 | ``` 165 | 166 | _render-compose-file_ after adding the above line: 167 | ``` yaml 168 | render-compose-file: 169 | name: Render Docker Compose File 170 | # Pass output of this workflow to another triggered by `workflow_run` event. 171 | runs-on: ubuntu-latest 172 | needs: 173 | - some-job 174 | outputs: 175 | compose-file-cache-key: ${{ steps.hash.outputs.hash }} 176 | steps: 177 | - name: Checkout git repo 178 | uses: actions/checkout@v3 179 | - name: Render Compose File 180 | run: | 181 | APP_IMAGE=${{ needs.some-job.outputs.tags }} 182 | export APP_IMAGE 183 | SOME_SECRET=${{secrets.SOME_SECRET}} 184 | export SOME_SECRET 185 | # Render simple template from environment variables. 186 | envsubst < docker-compose.uffizzi.yml > docker-compose.rendered.yml 187 | cat docker-compose.rendered.yml 188 | ``` 189 | 190 | Once you export the secret from the GHA workflow file, you can leverage the [`environment`](https://docs.uffizzi.com/references/compose-spec/#environment) directive in the `docker-compose.uffizzi.yml` file and through environment substitution, use this secret like below: 191 | ``` yaml 192 | my_app_fe: 193 | image: app_fe_image 194 | environment: 195 | SOME_SECRET: "${SOME_SECRET}" 196 | my_app_be: 197 | image: app_be_image 198 | environment: 199 | SOME_SECRET: "${SOME_SECRET}" 200 | ``` 201 | 202 | Sure! Here's the content formatted in markdown with code formatting: 203 | 204 | --- 205 | 206 | ## 7. HTTP 503 Errors in Ephemeral Environments (Node.js) 207 | 208 | Some users may experience 503 errors when running the tests against their Node.js applications deployed to Uffizzi ephemeral environments. These errors are usually encountered during the first run after the Uffizzi stack is spun up. 209 | 210 | **Symptoms** 211 | 212 | - 503 errors occurring, particularly during the first run after the Uffizzi stack is spun up. 213 | - Most of the tests failing due to the appearance of 503 errors. 214 | - Containers restarting 215 | - Application error: 216 | ``` 217 | "FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory error Command failed with signal "SIGABRT" 218 | ``` 219 | 220 | **Probable Cause** 221 | 222 | The 503 errors and heap-related failures are likely caused by the Node.js applications running within the web-app containers running out of memory. This is especially common when using Node.js for applications with high memory usage. 223 | 224 | **Troubleshooting Steps** 225 | 226 | 1. **Profile the Workload:** Start by profiling the workload and identifying the parts of the application that consume the most memory. Look for areas that might be improved to be more memory-efficient. This can be done using various Node.js profiling tools. 227 | 228 | 2. **Increase Node.js Heap Size:** Try increasing the heap size for Node.js by setting the environment variable `NODE_OPTIONS` to a value like `--max-old-space-size=400`. This can be done in the container's configuration or within the Node.js application itself. 229 | 230 | ```bash 231 | export NODE_OPTIONS=--max-old-space-size=400 232 | ``` 233 | 234 | 3. **Increase Container Memory Limit:** If increasing the Node.js heap size doesn't resolve the issue, you can try increasing the memory limit for the web-app container. This can be achieved by setting the memory limit to a higher value, such as `1000Mi` or `2000Mi`. After doing this, set the `NODE_OPTIONS` environment variable to a value like `--max-old-space-size=900` or `--max-old-space-size=1900`. 235 | 236 | ``` yaml 237 | web-app: 238 | ... 239 | deploy: 240 | resources: 241 | limits: 242 | memory: 2000M 243 | ``` 244 | 245 | ``` bash 246 | export NODE_OPTIONS=--max-old-space-size=900 247 | ``` 248 | 249 | 4. **Monitoring and Scaling:** Keep a close eye on the container's resource usage. Monitoring tools can help you understand memory consumption and performance bottlenecks. If necessary, consider manual scaling of the application to allocate more resources. 250 | 251 | 5. **Optimize Application Code:** Continue optimizing the application code to reduce memory usage. Techniques like memory caching, stream processing, and avoiding unnecessary object duplication can help in this regard. 252 | 253 | ## 8. Unauthorized: Bad Credentials (GitHub Integration) 254 | 255 | There are a few reason you might see the following error message in your account Settings > General page: 256 | 257 | ![GitHub Integration Error](../assets/images/bad-credentials.webp) 258 | 259 | For example, your credentials may have changed, you tried configuring your Uffizzi Team with a personal GitHub account (or vice versa), or perhaps something else. The easiest solution is to simply uninstall and then reinstall the Uffizzi Cloud GitHub App. This will re-establish the connection between your GitHub account and Uffizzi. 260 | 261 | To uninstall the Uffizzi Cloud GitHub App, go to GitHub.com > **Account** > **Settings** > **Applications** > **Installed GitHub Apps** > **Uffizzi Cloud** > **Configure** > **Uninstall “Uffizzi Cloud”**. 262 | 263 | ## **Other issues?** 264 | If you're having issues with your Uffizzi ephemeral environment that are not listed above, [get help on Slack](https://join.slack.com/t/uffizzi/shared_invite/zt-ffr4o3x0-J~0yVT6qgFV~wmGm19Ux9A) or [set up a Zoom call](https://calendly.com/d/yjr-gfc-g5w/uffizzi-support-call) with a member of our Technical Support Team. 265 | -------------------------------------------------------------------------------- /docs/virtual-cluster-environment.md: -------------------------------------------------------------------------------- 1 | # Create Virtual Cluster Environments from CI Pipelines 2 | 3 | !!! Tip 4 | If this is your first time using Uffizzi, we recommend following the [Quickstart Guide](quickstart.md) and [Using Uffizzi](using-uffizzi.md) to see a preconfigured example of how Uffizzi is configured. 5 | 6 | ## GitHub Actions Instructions 7 | 8 | Follow this example and our GitHub Actions: 9 | 10 | - [Example Configuration](https://github.com/UffizziCloud/quickstart-k8s) 11 | - [Cluster Action](https://github.com/UffizziCloud/cluster-action) 12 | - [Setup Action](https://github.com/UffizziCloud/setup-action) 13 | 14 | ### Overview of the process 15 | 16 | This guide will walk you through the process of creating Uffizzi cluster (uCluster) environments using Continuous Integration (CI) pipelines with Uffizzi. uCluster environments provide an isolated and reproducible environment for your applications, allowing you to easily test and deploy your code in a controlled setting. We will leverage the power of Uffizzi to set up and manage these environments directly from your CI pipelines. 17 | 18 | Adding the ability to create virtual cluster environments from you GitHub Actions workflow involves the following steps: 19 | 20 | 1. [Create a new Uffizzi Workflow](virtual-cluster-environment.md#create-a-new-uffizzi-workflow) - A file named `.github/workflows/uffizzi.yaml` in your repository and configure the workflow. 21 | 22 | 2. [Define build jobs](virtual-cluster-environment.md#define-build-jobs) - Build and push platform specific artifacts. 23 | 24 | 3. [Deploy Uffizzi Cluster](virtual-cluster-environment.md#deploy-uffizzi-cluster) - Create a uCluster with the application built in step 2. 25 | 26 | For a more detailed example and additional configurations, refer to the [complete example](https://github.com/UffizziCloud/quickstart-k8s/blob/main/.github/workflows/uffizzi.yml) in the UffizziCloud repository. 27 | 28 | ### Create a new Uffizzi Workflow 29 | 30 | In this section, we'll create a new GitHub workflow within the application repository -- Add a name, then define when it runs -- also provide the following permissions: 31 | ```yaml 32 | name: Uffizzi Cluster Quickstart 33 | 34 | on: 35 | pull_request: 36 | types: [opened,reopened,synchronize,closed] 37 | 38 | permissions: 39 | contents: read 40 | pull-requests: write 41 | id-token: write 42 | ``` 43 | 44 | ### Define build jobs 45 | 46 | For each of the application components define the various configurations required to build the application. For example, Replace build-foo and build-bar with your actual build job names and configurations: 47 | ```yaml 48 | jobs: 49 | build-foo: 50 | ... 51 | build-bar: 52 | ... 53 | ``` 54 | 55 | ### Deploy Uffizzi Cluster 56 | 57 | Create a cluster job within the workflow that utilizes the Uffizzi cluster-action. This job will deploy your application to the uCluster. As seen in the code snippet -- the `UffizziCloud/cluster-action@main` action is called with the `cluster-name: pr-${{ github.event.pull_request.number }}` parameter. This creates a new uffizzi cluster (uCluster) with the name pr-{pr number}. 58 | 59 | In this workflow, we use Kustomize to customize our Kubernetes manifests before applying them to the Uffizzi Virtual Cluster. Here's how it works: 60 | 61 | - We fetch the Docker image tags generated by previous build jobs (e.g., needs.build-vote.outputs.tags). 62 | - We use Kustomize to update the image references in our Kubernetes manifests, ensuring they point to the newly built and pushed images. 63 | 64 | ```yaml 65 | uffizzi-cluster: 66 | name: Deploy to Uffizzi Virtual Cluster 67 | ... 68 | ... 69 | # Create a uCluster with cluster-name as pr-number 70 | - name: Connect to Virtual Cluster 71 | uses: UffizziCloud/cluster-action@main 72 | with: 73 | cluster-name: pr-${{ github.event.pull_request.number }} 74 | 75 | # Edit manifests and Apply 76 | - name: Kustomize and Apply Manifests 77 | id: prev 78 | run: | 79 | # Change the image name to those just built and pushed. 80 | kustomize edit set image my-registry/image_name=${{ needs.build-vote.outputs.tags }} 81 | kustomize edit set image my-registry/image_name=${{ needs.build-result.outputs.tags }} 82 | 83 | # Apply kustomized manifests to virtual cluster. 84 | kubectl apply --kustomize . --kubeconfig ./kubeconfig 85 | ``` 86 | 87 | Alternatively, the `helm --set` command can be integrated into the workflow to modify image references within a Helm chart `values.yaml` file: 88 | 89 | ```yaml 90 | # Apply Harbor Helm Chart 91 | - name: Apply Helm Chart 92 | id: helm 93 | run: | 94 | export vote=$(echo ${{ needs.build-vote.outputs.tags }} 95 | export result=$(echo ${{ needs.build-result.outputs.tags }} 96 | 97 | export KUBECONFIG="`pwd`/kubeconfig" 98 | helm repo add 99 | 100 | helm upgrade --install my-release \ 101 | --set vote.image.repository=${REPO_portal} \ 102 | --set vote.image.tag=24h \ 103 | --set result.image.repository=${REPO_core} \ 104 | --set result.image.tag=24h \ 105 | / --values=values.yaml 106 | ``` 107 | 108 | ## GitLab CI Instructions 109 | 110 | ### Introduction 111 | 112 | This guide outlines how to integrate Uffizzi virtual cluster environments into your GitLab CI/CD pipelines. GitLab CI allows you to automate tasks triggered by events like pull requests, ensuring a smooth and consistent development and deployment process. Check out the [Example Configuration](https://gitlab.com/uffizzicloud/quickstart-k8s/-/blob/main/.gitlab-ci.yml) for GitLab CI integration details. 113 | 114 | ### Pipeline Stages 115 | 116 | The GitLab pipeline consists of five main stages, each serving a specific purpose: 117 | ```yaml hl_lines="5-10" title=".gitlab-ci.yml" 118 | ... 119 | services: 120 | ... 121 | 122 | stages: 123 | - build 124 | - uffizzi_cluster_deploy 125 | - kustomize_apply 126 | - add_comment 127 | - uffizzi_cluster_delete 128 | ... 129 | ``` 130 | 131 | #### **Build** 132 | The `build` stage handles the building and pushing of application images to a temporary Uffizzi registry. This stage ensures that your application components are packaged and ready for deployment. 133 | 134 | #### **Uffizzi Cluster Deploy** 135 | The `uffizzi_cluster_deploy` stage refers to the `deploy_cluster_environment` job, which is defined in the included `cluster.gitlab-ci.yml` file. This job is responsible for deploying a Uffizzi cluster environment for the merge request. 136 | 137 | This job performs the following tasks: 138 | 139 | - Checks if the environment already exists and updates it if necessary. 140 | - Logs in to Uffizzi using identity tokens. 141 | - Creates or updates the Uffizzi cluster environment for the merge request. 142 | - Configures the Kubernetes cluster access. 143 | 144 | ```yaml hl_lines="1-2" title=".gitlab-ci.yml" 145 | include: 146 | - "https://gitlab.com/uffizzicloud/cluster-action/raw/main/cluster.gitlab-ci.yml" 147 | 148 | variables: 149 | ... 150 | ``` 151 | 152 | #### **Kustomize Apply** 153 | The `kustomize_apply` stage refers to the `kustomize_template` job within the `cluster.gitlab-ci.yml` file. This job applies Kubernetes customizations using kustomize and ensures that your application is configured correctly for the Uffizzi environment. 154 | 155 | This job performs the following tasks: 156 | 157 | - Downloads kubectl and kustomize. 158 | - Repeats some of the steps from the uffizzi_cluster_deploy stage for authentication. 159 | - Applies K8s manifests using kustomize. 160 | 161 | ```yaml title="cluster.gitlab-ci.yml" 162 | .kustomize_template: &kustomize_template 163 | stage: kustomize_apply 164 | rules: 165 | - if: $CI_MERGE_REQUEST_ID 166 | ... 167 | ``` 168 | 169 | #### **Add Comment** 170 | The `add_comment` stage adds important Uffizzi cluster command details as comments to the merge request. This helps developers access and manage the Uffizzi cluster environment effectively. 171 | 172 | #### **Uffizzi Cluster Delete** 173 | The `uffizzi_cluster_delete` stage deletes the Uffizzi cluster once the merge request is closed. This ensures that resources are cleaned up when they are no longer needed. 174 | 175 | Now you're ready to harness the power of Uffizzi Virtual Cluster Environments within your CI/CD pipelines. If you have any questions or need assistance, feel free to reach out to our support team. Happy coding! -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | # Project information 2 | site_name: Uffizzi Docs 3 | site_author: Uffizzi.com 4 | site_description: >- 5 | Uffizzi Documentation 6 | site_url: https://docs.uffizzi.com/ 7 | # Repository 8 | repo_url: https://github.com/UffizziCloud/docs 9 | repo_name: UffizziCloud/docs 10 | edit_uri: edit/main/docs/ 11 | 12 | # Copyright 13 | copyright: Copyright © 2023 Uffizzi 14 | 15 | # Styling 16 | extra_css: 17 | - stylesheets/extra.css 18 | theme: 19 | name: material 20 | locale: en_US 21 | logo: assets/images/u-logo.svg 22 | favicon: assets/images/favicon.png 23 | features: 24 | - content.code.annotate 25 | - navigation.instant 26 | - navigation.tabs 27 | - navigation.tabs.sticky 28 | - navigation.tracking 29 | - navigation.sections 30 | - navigation.expand 31 | - navigation.indexes 32 | - navigation.top 33 | - footer.autohide 34 | - search.highlight 35 | - search.share 36 | - search.suggest 37 | 38 | # Plugins 39 | plugins: 40 | - search 41 | - minify: 42 | minify_html: true 43 | 44 | # Customization 45 | extra: 46 | social: 47 | - icon: fontawesome/brands/slack 48 | link: https://join.slack.com/t/uffizzi/shared_invite/zt-ffr4o3x0-J~0yVT6qgFV~wmGm19Ux9A 49 | - icon: fontawesome/brands/twitter 50 | link: https://twitter.com/Uffizzi_ 51 | - icon: fontawesome/brands/docker 52 | link: https://hub.docker.com/orgs/uffizzi 53 | - icon: fontawesome/brands/github 54 | link: https://github.com/UffizziCloud 55 | generator: true 56 | analytics: 57 | provider: google 58 | property: UA-157967585-1 59 | homepage: https://www.uffizzi.com 60 | 61 | # Extensions 62 | markdown_extensions: 63 | - admonition 64 | - abbr 65 | - attr_list 66 | - def_list 67 | - footnotes 68 | - meta 69 | - md_in_html 70 | - toc: 71 | permalink: true 72 | - pymdownx.arithmatex: 73 | generic: true 74 | - pymdownx.betterem: 75 | smart_enable: all 76 | - pymdownx.caret 77 | - pymdownx.details 78 | - pymdownx.emoji: 79 | emoji_index: !!python/name:materialx.emoji.twemoji 80 | emoji_generator: !!python/name:materialx.emoji.to_svg 81 | - pymdownx.highlight: 82 | anchor_linenums: true 83 | line_spans: __span 84 | pygments_lang_class: true 85 | - pymdownx.inlinehilite 86 | - pymdownx.keys 87 | - pymdownx.magiclink: 88 | repo_url_shorthand: true 89 | user: squidfunk 90 | repo: mkdocs-material 91 | - pymdownx.mark 92 | - pymdownx.smartsymbols 93 | - pymdownx.snippets 94 | - pymdownx.superfences: 95 | custom_fences: 96 | - name: mermaid 97 | class: mermaid-experimental 98 | format: !!python/name:pymdownx.superfences.fence_code_format 99 | - pymdownx.tabbed: 100 | alternate_style: true 101 | - pymdownx.tasklist: 102 | custom_checkbox: true 103 | - pymdownx.tilde 104 | 105 | # Page tree 106 | nav: 107 | - Home: 108 | - Home: index.md 109 | - Quickstart Guide: quickstart.md 110 | - Installation: install.md 111 | - Using Uffizzi: using-uffizzi.md 112 | - Virtual Cluster Environments from CI Pipelines: virtual-cluster-environment.md 113 | - Docker Compose Environments from CI Pipelines: docker-compose-environment.md 114 | - Architecture: architecture.md 115 | - How-To: 116 | - Uffizzi CI: quickstart-uffizzi-ci.md 117 | - Demo on Uffizzi button: guides/demo-on-uffizzi.md 118 | - Set up your account: guides/set-up-your-account.md 119 | - Expose multiple routes: guides/expose-multiple-routes.md 120 | - Configure password-protected environments: guides/password-protected.md 121 | - Authenticate with a container registry: guides/container-registry-integrations.md 122 | - Add environment variables: guides/environment-variables.md 123 | - Add secrets: guides/secrets.md 124 | - Check logs: guides/logs.md 125 | - Configure SSO: guides/single-sign-on.md 126 | - Microservices on Uffizzi: guides/support-microservices-in-ephemeral-environments-with-nginx.md 127 | - GitHub Environments: guides/github-environment.md 128 | - Topics: 129 | - Virtual Clusters: topics/virtual-clusters.md 130 | - Teams and Accounts: topics/teams-and-accounts.md 131 | - Role-based access (RBAC): topics/rbac.md 132 | - Networking and architecture: topics/networking.md 133 | - OpenID Connect (OIDC): topics/oidc.md 134 | - Why Uffizzi?: topics/why-uffizzi.md 135 | - Continuous Previews: topics/continuous-previews.md 136 | - CI/CD + CP: topics/ci-cd-registry.md 137 | - Single-Page Applications: topics/single-page-applications.md 138 | - Docker Extensions Partner: topics/docker-extension-partner.md 139 | - References: 140 | - Command-line Reference: references/cli.md 141 | - Docker Compose for Uffizzi: references/compose-spec.md 142 | - Example Uffizzi Compose: references/example-compose.md 143 | - Uffizzi CI: references/uffizzi-ci.md 144 | - Uffizzi Environment URL: references/uffizzi-environment-variables.md 145 | - Troubleshooting: 146 | - Most common problems: troubleshooting/most-common-problems.md 147 | - Debugging: troubleshooting/debugging.md 148 | - File or Directory is Too Large Error: troubleshooting/file-or-directory-is-too-large.md 149 | -------------------------------------------------------------------------------- /nginx/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | #listen [::]:80; 4 | server_name docs.uffizzi.com localhost; 5 | 6 | #access_log /var/log/nginx/host.access.log main; 7 | 8 | location / { 9 | root /usr/share/nginx/html; 10 | index index.html; 11 | } 12 | 13 | error_page 404 /404.html; 14 | 15 | # redirect server error pages to the static page /50x.html 16 | # 17 | error_page 500 502 503 504 /50x.html; 18 | location = /50x.html { 19 | root /usr/share/nginx/html; 20 | } 21 | 22 | default_type text/html; 23 | 24 | keepalive_requests 100; 25 | 26 | server_tokens off; 27 | } 28 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs 2 | mkdocs-material==8.5.8 3 | mkdocs-minify-plugin 4 | -------------------------------------------------------------------------------- /uffizzi-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | docs: 3 | build: 4 | context: https://github.com/UffizziCloud/docs#main 5 | dockerfile: Dockerfile 6 | deploy: 7 | resources: 8 | limits: 9 | memory: 125M 10 | 11 | x-uffizzi: 12 | ingress: 13 | service: docs 14 | port: 80 15 | continuous_preview: 16 | deploy_preview_when_pull_request_is_opened: true 17 | delete_preview_when_pull_request_is_closed: true 18 | share_to_github: true 19 | --------------------------------------------------------------------------------