diff --git a/docs/deployment/digital-ocean-apps-iac.mdx b/docs/deployment/digital-ocean-apps-iac.mdx index 762a1419a..994c542bb 100644 --- a/docs/deployment/digital-ocean-apps-iac.mdx +++ b/docs/deployment/digital-ocean-apps-iac.mdx @@ -2,6 +2,8 @@ title: "Digital Ocean Apps (IaC)" --- +import GithubActionsWithPrebuiltImagesSnippet from '/snippets/github-actions-with-prebuilt-docker-images-for-do.mdx'; + There is a simplified deployment type without Kubernetes. This type is **recommended** for most new applications because it allows you to set up infrastructure faster and doesn't require additional DevOps knowledge from the development team. You can switch to a more complex Kubernetes solution when your application will be at scale. It's a step-by-step Ship deployment guide. We will use the [Digital Ocean Apps](https://www.digitalocean.com/products/app-platform) and [GitHub Actions](https://github.com/features/actions) for automated deployment. [Mongo Atlas](https://www.mongodb.com/) and [Redis Cloud](https://redis.com/try-free/) for databases deployment, [Cloudflare](https://www.cloudflare.com/) for DNS and SSL configuration and [Pulumi](https://www.pulumi.com/) for Infrastructure as Code @@ -273,6 +275,9 @@ Done! Application deployed and can be accessed by provided domain. ![Deployed application](/images/deployed-application.png) +## Github Actions with prebuilt Container Images (Optional) + + ## Logging (optional) ### Build-in diff --git a/docs/deployment/digital-ocean-apps.mdx b/docs/deployment/digital-ocean-apps.mdx index 97cffc13a..19bb608e3 100644 --- a/docs/deployment/digital-ocean-apps.mdx +++ b/docs/deployment/digital-ocean-apps.mdx @@ -2,6 +2,8 @@ title: "Digital Ocean Apps" --- +import GithubActionsWithPrebuiltImagesSnippet from '/snippets/github-actions-with-prebuilt-docker-images-for-do.mdx'; + There is a simplified deployment type without Kubernetes. This type is **recommended** for most new applications because it allows you to set up infrastructure faster and doesn't require additional DevOps knowledge from the development team. You can switch to a more complex Kubernetes solution when your application will be at scale. @@ -237,6 +239,9 @@ Done! Application deployed and can be accessed by provided domain. ![Deployed application](/images/deployed-application.png) +## Github Actions with prebuilt Container Images (Optional) + + ## Set up migrator and scheduler (Optional) Digital Ocean Apps allows configuring additional resources within one application, which can serve as background workers and jobs, and a scheduler to run before/after the deployment process. diff --git a/docs/images/create-digital-ocean-container-registry.png b/docs/images/create-digital-ocean-container-registry.png new file mode 100644 index 000000000..f66f793eb Binary files /dev/null and b/docs/images/create-digital-ocean-container-registry.png differ diff --git a/docs/images/deploy-actions-compressions.png b/docs/images/deploy-actions-compressions.png new file mode 100644 index 000000000..8c4045234 Binary files /dev/null and b/docs/images/deploy-actions-compressions.png differ diff --git a/docs/images/do-registry-github-secrets.png b/docs/images/do-registry-github-secrets.png new file mode 100644 index 000000000..2c0be88a2 Binary files /dev/null and b/docs/images/do-registry-github-secrets.png differ diff --git a/docs/images/pushed-images-in-docr.png b/docs/images/pushed-images-in-docr.png new file mode 100644 index 000000000..0ee84d364 Binary files /dev/null and b/docs/images/pushed-images-in-docr.png differ diff --git a/docs/images/recent-image-tag-in-docr.png b/docs/images/recent-image-tag-in-docr.png new file mode 100644 index 000000000..8220c2106 Binary files /dev/null and b/docs/images/recent-image-tag-in-docr.png differ diff --git a/docs/images/run-build-and-push-do-image-results.png b/docs/images/run-build-and-push-do-image-results.png new file mode 100644 index 000000000..7afe50e9e Binary files /dev/null and b/docs/images/run-build-and-push-do-image-results.png differ diff --git a/docs/images/select-do-registry-plan.png b/docs/images/select-do-registry-plan.png new file mode 100644 index 000000000..ea1d7db7c Binary files /dev/null and b/docs/images/select-do-registry-plan.png differ diff --git a/docs/snippets/github-actions-with-prebuilt-docker-images-for-do.mdx b/docs/snippets/github-actions-with-prebuilt-docker-images-for-do.mdx new file mode 100644 index 000000000..5bf7843d2 --- /dev/null +++ b/docs/snippets/github-actions-with-prebuilt-docker-images-for-do.mdx @@ -0,0 +1,422 @@ +Deploying an application to DigitalOcean can be done using prebuilt container images stored in a container registry such as [Digital Ocean Container Registry](https://www.digitalocean.com/products/container-registry). Using prebuilt images helps speed up deployment, eliminate the need to install dependencies on the server, and ensure build reproducibility. + +| When to use | DO builds from repo (App Platform) | Prebuilt image from GH Actions + DOCR | +| ---------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------ | +| Small applications | Can deploy directly | Can also deploy, but optional for small apps | +| Large applications | May fail or be slow if build requires significant resources and memory | Essential for large projects with high compute/memory requirements | +| Deployment speed | Slower; builds happen during deployment | Faster; images are prebuilt in CI/CD and pushed ready-to-use | +| Reliability | Builds depend on server environment | Better consistency and reproducibility in production | +| Dependencies | Installed on server during build | Already included in prebuilt image | + +See speed comparison below. + +![Deploy actions compressions](/images/deploy-actions-compressions.png) + +To use prebuilt container images, navigate to the **DigitalOcean Container Registry** tab and click the **Create a Container Registry** button. + +![Digital Ocean Container Registry](/images/create-digital-ocean-container-registry.png) + + + + Select the Basic plan, choose the region that matches your app’s region, specify a name for the container registry, and click **Create Registry**. + + ![Select DO container registry plan](/images/select-do-registry-plan.png) + + + + Add two new GitHub Actions workflows to build and push updated images so they can be attached to your DigitalOcean Apps. + + + Don’t forget to replace `ship-demo` in `registry.digitalocean.com/ship-demo/ship-demo-...` with your own values from DigitalOcean. + + + ```yaml .github/workflows/api-staging-build-and-push-image.yml expandable + name: Build and Push Staging API Image to DigitalOcean + + on: + push: + branches: [main] + paths: + - "apps/api/**" + - "packages/**" + workflow_dispatch: + + permissions: + contents: read + packages: write + + jobs: + build: + name: Build and Push Docker Images + runs-on: ubuntu-latest + strategy: + matrix: + include: + - app_name: api + dockerfile: apps/api/Dockerfile + - app_name: migrator + dockerfile: apps/api/Dockerfile.migrator + - app_name: scheduler + dockerfile: apps/api/Dockerfile.scheduler + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: registry.digitalocean.com + username: ${{ secrets.DO_USERNAME }} + password: ${{ secrets.DO_ACCESS_TOKEN }} + + - name: Build and Push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: linux/amd64 + file: ${{ matrix.dockerfile }} + tags: registry.digitalocean.com/ship-demo/ship-demo-${{ matrix.app_name }}:${{ github.sha }} + target: runner + cache-from: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-${{ matrix.app_name }}:cache + cache-to: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-${{ matrix.app_name }}:cache,mode=max + ``` + + ```yaml .github/workflows/web-staging-build-and-push-image.yml expandable + name: Build and Push Staging Web Image to DigitalOcean + + on: + push: + branches: [main] + paths: + - "apps/web/**" + - "packages/**" + workflow_dispatch: + + permissions: + contents: read + packages: write + + jobs: + build: + name: Build and Push Docker Images + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: registry.digitalocean.com + username: ${{ secrets.DO_USERNAME }} + password: ${{ secrets.DO_ACCESS_TOKEN }} + + - name: Build and Push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: linux/amd64 + file: ./apps/web/Dockerfile + tags: registry.digitalocean.com/ship-demo/ship-demo-web:${{ github.sha }} + target: runner + cache-from: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-web:cache + cache-to: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-web:cache,mode=max + build-args: | + APP_ENV=staging + + ``` + + + + Add 3 new github secrets: + - `DO_USERNAME` - the email of your DigitalOcean account; + - `DO_WEB_STAGING_APP_NAME` - the name of the web app; + - `DO_API_STAGING_APP_NAME` - the name of the API app. + + ![Create new github secrets for DO container registry](/images/do-registry-github-secrets.png) + + Run 2 new workflows manually to push the initial images to the DigitalOcean Container Registry. + + ![Run and Build Docker images result](/images/run-build-and-push-do-image-results.png) + + + + Navigate to your DigitalOcean Container Registry. You should see 4 newly added repositories, as shown in the screenshot below. + + ![Pushed Docker Images in DOCR](/images/pushed-images-in-docr.png) + + + + Open Application Spec (settings tab) and **remove** the following properties for **api**, **migrator** and **scheduler**: + + - `dockerfile_path` + - `github` + - `source_dir` + + **Migrator** is placed in the `jobs` section. + **Scheduler** is placed in the `workers` section. + **Api** is placed in the `services` section. + + You can also find it by name of the resource. + + Now you need to add a configuration to work with prebuilt images: + Add `image` property for **api**, **migrator** and **scheduler**. + + | Property | Description | Example | + | ------ | ---------------------------------------------------------------- | ------------------------------------------ | + | registry | Name of created Digital Ocean registry | `ship-demo` | + | registry_type | Container registry’s service. For our solution it will be `DOCR`.| `DOCR` | + | repository | Image repository’s name | `ship-demo-api` | + | tag | Image’s latest tag. Check this value in your Image's repository | `55267dd70af17cb0e770ceed696f3fe9e5f1ee8d` | + + You can find the recent tag for your app image in **container registry** as shown in the screenshot below. + + ![Recent Image tag in DOCR](/images/recent-image-tag-in-docr.png) + + ```yaml API App Spec example expandable lines + services: + - image: # [!code ++:5] + registry: YOUR_DO_REGISTRY_NAME + registry_type: DOCR + repository: YOUR_DO_API_REPOSITORY_NAME + tag: YOUR_RECENT_API_IMAGE_TAG + - dockerfile_path: apps/api/Dockerfile # [!code --] + github: # [!code --:3] + branch: main + repo: paralect/ship + http_port: 3001 + instance_count: 1 + instance_size_slug: apps-s-1vcpu-0.5gb + name: ship-demo-api + source_dir: . # [!code --] + + jobs: + - image: # [!code ++:5] + registry: YOUR_DO_REGISTRY_NAME + registry_type: DOCR + repository: YOUR_DO_MIGRATOR_REPOSITORY_NAME + tag: YOUR_RECENT_MIGRATOR_IMAGE_TAG + - dockerfile_path: apps/api/Dockerfile.migrator # [!code --] + github: # [!code --:3] + branch: main + repo: paralect/ship + instance_count: 1 + instance_size_slug: apps-s-1vcpu-0.5gb + kind: PRE_DEPLOY + name: ship-demo-migrator + source_dir: . # [!code --] + + workers: + - image: # [!code ++:5] + registry: YOUR_DO_REGISTRY_NAME + registry_type: DOCR + repository: YOUR_DO_SCHEDULER_REPOSITORY_NAME + tag: YOUR_RECENT_SCHEDULER_IMAGE_TAG + - dockerfile_path: apps/api/Dockerfile.scheduler # [!code --] + github: # [!code --:3] + branch: main + repo: paralect/ship + instance_count: 1 + instance_size_slug: apps-s-1vcpu-1gb + name: ship-demo-scheduler + source_dir: . # [!code --] + ``` + + + + Do the same actions for web app. + + ```yaml WEB App Spec example lines + services: + - image: # [!code ++:5] + registry: YOUR_DO_REGISTRY_NAME + registry_type: DOCR + repository: YOUR_DO_WEB_REPOSITORY_NAME + tag: YOUR_RECENT_WEB_IMAGE_TAG + - dockerfile_path: apps/web/Dockerfile # [!code --] + github: # [!code --:3] + branch: main + repo: paralect/ship + http_port: 3002 + instance_count: 1 + instance_size_slug: apps-s-1vcpu-0.5gb + name: ship-demo-web + source_dir: . # [!code --] + ``` + + + + Replace the old deployment action with the new one and **remove** old two actions: `.github/workflows/api-staging-build-and-push-image.yml` and `.github/workflows/web-staging-build-and-push-image.yml`. + + + Don’t forget to replace `ship-demo` in `registry.digitalocean.com/ship-demo/ship-demo-...` with your own values from DigitalOcean. + + + ```yaml .github/workflows/api-staging.yml + name: "Staging application API deployment" + + on: + push: + branches: [main] + paths: + - "apps/api/**" + - "packages/**" + workflow_dispatch: + inputs: + logLevel: + description: "Log level" + required: true + default: "warning" + tags: + description: "Test scenario" + required: false + + permissions: + contents: read + packages: write + + jobs: + build: + name: Build and Push Docker Images + runs-on: ubuntu-latest + strategy: + matrix: + include: + - app_name: api + dockerfile: apps/api/Dockerfile + - app_name: migrator + dockerfile: apps/api/Dockerfile.migrator + - app_name: scheduler + dockerfile: apps/api/Dockerfile.scheduler + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: registry.digitalocean.com + username: ${{ secrets.DO_USERNAME }} + password: ${{ secrets.DO_ACCESS_TOKEN }} + + - name: Build and Push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: linux/amd64 + file: ${{ matrix.dockerfile }} + tags: registry.digitalocean.com/ship-demo/ship-demo-${{ matrix.app_name }}:${{ github.sha }} + target: runner + cache-from: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-${{ matrix.app_name }}:cache + cache-to: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-${{ matrix.app_name }}:cache,mode=max + + deploy: + name: Deploy to DigitalOcean + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to DigitalOcean App Platform + uses: digitalocean/app_action/deploy@v2 + env: + IMAGE_TAG_SHIP_DEMO_API: ${{ github.sha }} + IMAGE_TAG_SHIP_DEMO_MIGRATOR: ${{ github.sha }} + IMAGE_TAG_SHIP_DEMO_SCHEDULER: ${{ github.sha }} + with: + token: ${{ secrets.DO_ACCESS_TOKEN }} + app_name: ${{ secrets.DO_API_STAGING_APP_NAME }} + ``` + + ```yaml .github/workflows/web-staging.yml + name: "Staging application Web deployment" + + on: + push: + branches: [main] + paths: + - "apps/web/**" + - "packages/**" + workflow_dispatch: + inputs: + logLevel: + description: "Log level" + required: true + default: "warning" + tags: + description: "Test scenario" + required: false + + jobs: + build: + name: Build and Push Docker Images + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + registry: registry.digitalocean.com + username: ${{ secrets.DO_USERNAME }} + password: ${{ secrets.DO_ACCESS_TOKEN }} + + - name: Build and Push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: linux/amd64 + file: ./apps/web/Dockerfile + tags: registry.digitalocean.com/ship-demo/ship-demo-web:${{ github.sha }} + target: runner + cache-from: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-web:cache + cache-to: type=registry,ref=registry.digitalocean.com/ship-demo/ship-demo-web:cache,mode=max + build-args: | + APP_ENV=staging + + deploy: + name: Deploy to DigitalOcean + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to DigitalOcean App Platform + uses: digitalocean/app_action/deploy@v2 + env: + IMAGE_TAG_SHIP_DEMO_WEB: ${{ github.sha }} + with: + token: ${{ secrets.DO_ACCESS_TOKEN }} + app_name: ${{ secrets.DO_WEB_STAGING_APP_NAME }} + ``` + + + The name of the environment variable for the image tag must meet this requirement IMAGE_TAG_$component-name. + + +