1
0
mirror of https://github.com/docker/docs.git synced 2026-10-23 18:09:02 +03:00

Revamp the guides section: taxonomy, single-page structure, and new landing/filter UX (#25338)

## What

A full revamp of the `/guides` section — taxonomy, structure, and UX.

Preview: https://deploy-preview-25338--docsdocker.netlify.app/guides/

### Taxonomy & structure
- Replaces the sprawling 24-tag set with a focused 9-tag taxonomy
aligned to use case / SDLC: **Languages & frameworks, AI, Testing,
CI/CD, Security, Databases, Deployment, Admin, Hands-on labs**.
- Removes the languages taxonomy entirely (`data/languages.yaml` and all
`languages:` front matter).
- Collapses all multi-page guide series into single pages, with aliases
so old sub-page URLs continue to resolve.
- Deletes redirect-only shim pages and flattens directory-wrapped single
pages.

### Landing page (`/guides/`)
- A clean index: hero, then category sections listing each guide as a
plain **title / summary** row.
- **Browse rail** (sticky, left): click a topic to filter the page to
just that topic's guides; "All guides" resets. A count + Clear bar
appears while filtering.
- **Text filter**: instant client-side search over title, summary, and
tags. Topic filter and text search are mutually exclusive and share the
same flat-list view.
- No more "Featured guides" section.

### Guide content pages
- Removes the left sidebar for the guides section (mobile drawer kept).
- Centered reading column (`92ch`) with the TOC taking the remaining
width.
- Summary rendered as a lead paragraph under the h1.
- TOC scrollbar auto-hides until hover; breadcrumbs render at a
consistent size inside and outside `prose`.

## Notes
- Deep full-text search across guide bodies is still handled by the
existing site-wide Pagefind (⌘K); the landing filter is the fast
metadata-narrowing surface.
- `series.html` is retained — it's still used by `get-started` pages.

## Validation
- Site builds clean locally (Hugo dev server, no errors / broken refs).
- All collapsed sub-page URLs redirect via aliases.

## Follow-ups

- Prune guides that we no longer need/want
- Tighten the guides that span too many concepts (e.g. language guides;
remove cicd/deploy/sscs)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
David Karlsson
2026-07-01 10:47:10 +02:00
committed by GitHub
parent ef2165d47c
commit f02e2a5633
302 changed files with 23207 additions and 24782 deletions

View File

@@ -208,6 +208,33 @@
}
}
}
@utility scrollbar-hover {
/* Firefox: hide the thumb until hover */
scrollbar-width: thin;
scrollbar-color: transparent transparent;
&:hover {
scrollbar-color: var(--color-gray-400) transparent;
}
.dark &:hover {
scrollbar-color: var(--color-gray-600) transparent;
}
/* WebKit: reserve the track, reveal the thumb only on hover */
&::-webkit-scrollbar {
width: 8px;
height: 8px;
}
&::-webkit-scrollbar-thumb {
border-radius: 9999px;
background-color: transparent;
}
&:hover::-webkit-scrollbar-thumb {
background-color: var(--color-gray-400);
}
.dark &:hover::-webkit-scrollbar-thumb {
background-color: var(--color-gray-600);
}
}
@utility chip {
@apply border-divider-light dark:border-divider-dark inline-flex items-center gap-1 rounded-full border bg-gray-100 px-2 text-sm text-gray-800 select-none dark:bg-gray-700 dark:text-gray-200;
}
@@ -217,7 +244,17 @@
}
@utility breadcrumbs {
font-size: 90%;
/* Absolute size so breadcrumbs render identically inside and outside prose */
font-size: calc(var(--text-base) * 0.9);
}
/* Guides landing: collapse section spacing into a flat list while filtering.
Grouped spacing is the static default; this only applies once the page is
being filtered, so it never affects first paint (no layout jank). */
.guides-flat > section {
border-top-width: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
}
@utility topbar-button {

View File

@@ -1,7 +1,7 @@
---
title: Docker guides
linkTitle: Guides
description: Explore the Docker guides
description: Step-by-step tutorials, organized by what you're trying to do.
keywords: docker, guides, tutorials, learning paths, getting started
params:
icon: book-open
@@ -9,13 +9,17 @@ layout: landing
aliases:
- /guides/language/
- /language/
- /guides/dhi-from-doi/
- /guides/dhi-from-wolfi/
- /guides/dhi-go-example/
- /guides/dhi-nodejs-example/
- /guides/dhi-python-example/
- /guides/lab-docker-for-ai-redirect/
- /learning-paths/
---
Explore our collection of guides to learn how Docker can optimize your
development workflows and how to use it with specific languages, frameworks, or
technologies.
Explore guides to learn how Docker can optimize your development workflows and
how to use it with specific languages, frameworks, or technologies.
Can't find the guide you're looking for? Open an issue on the
[docker/docs](https://github.com/docker/docs/issues/new) repository to let us
know.
[docker/docs](https://github.com/docker/docs/issues/new) repository.

View File

@@ -1,108 +0,0 @@
---
title: Set up your company for success with Docker
linkTitle: Admin set up
summary: Get the most out of Docker by streamlining workflows, standardizing development environments, and ensuring smooth deployments across your company.
description: Learn how to onboard your company and take advantage of all of the Docker products and features.
keywords: admin, onboarding, deployment, organization setup, docker business, rollout
tags: [admin]
params:
time: 20 minutes
image:
resource_links:
- title: Overview of Administration in Docker
url: /admin/
- title: Single sign-on
url: /security/for-admins/single-sign-on/
- title: Enforce sign-in
url: /security/for-admins/enforce-sign-in/
- title: Roles and permissions
url: /security/for-admins/roles-and-permissions/
- title: Settings Management
url: /security/for-admins/hardened-desktop/settings-management/
- title: Registry Access Management
url: /security/for-admins/hardened-desktop/registry-access-management/
- title: Image Access Management
url: /security/for-admins/hardened-desktop/image-access-management/
- title: Docker subscription information
url: "https://www.docker.com/pricing?ref=Docs&refAction=DocsGuidesAdminSetup"
---
Docker's tools provide a scalable, secure platform that empowers your
developers to create, ship, and run applications faster. As an administrator,
you can streamline workflows, standardize development environments, and ensure
smooth deployments across your organization.
By configuring Docker products to suit your company's needs, you can optimize
performance, simplify user management, and maintain control over resources.
This guide helps you set up and configure Docker products to maximize
productivity and success for your team while meeting compliance and security
policies.
## Who’s this for?
- Administrators responsible for managing Docker environments within their
organization
- IT leaders looking to streamline development and deployment workflows
- Teams aiming to standardize application environments across multiple users
- Organizations seeking to optimize their use of Docker products for greater
scalability and efficiency
- Organizations with a
[Docker Business subscription](https://www.docker.com/pricing?ref=DocsGuides&refAction=DocsGuidesCTAClicked)
## What you’ll learn
- Why signing into your company's Docker organization provides access to usage
data and enhanced functionality
- How to standardize Docker Desktop versions and settings to create a consistent
baseline for all users, while allowing flexibility for advanced developers
- Strategies for implementing Docker's security configurations to meet company
IT and software development security requirements without hindering developer productivity
## Features covered
This guide covers the following Docker features:
- [Organizations](/manuals/admin/organization/_index.md): The core structure
for managing your Docker environment, grouping users, teams, and image
repositories. Your organization was created with your subscription and is
managed by one or more owners. Users signed into the organization are
assigned seats based on the purchased subscription.
- [Enforce sign-in](/manuals/enterprise/security/enforce-sign-in/_index.md):
By default, Docker Desktop doesn't require sign-in. You can configure
settings to enforce this and ensure your developers sign in to your
Docker organization.
- [SSO](/manuals/enterprise/security/single-sign-on/_index.md): Without SSO,
user management in a Docker organization is manual. Setting
up an SSO connection between your identity provider and Docker ensures
compliance with your security policy and automates user provisioning. Adding
SCIM further automates user provisioning and de-provisioning.
- General and security settings: Configuring key settings ensures smooth
onboarding and usage of Docker products within your environment. You can also
enable security features based on your company's specific security needs.
## Who needs to be involved
- Docker organization owner: Must be involved in the process and is required
for several key steps
- DNS team: Needed during the SSO setup to verify the company domain
- MDM team: Responsible for distributing Docker-specific configuration files to
developer machines
- Identity Provider team: Required for configuring the identity provider and
establishing the SSO connection during setup
- Development lead: A development lead with knowledge of Docker configurations
to help establish a baseline for developer settings
- IT team: An IT representative familiar with company desktop policies to
assist with aligning Docker configuration to those policies
- Infosec: A security team member with knowledge of company development
security policies to help configure security features
- Docker testers: A small group of developers to test the new settings and
configurations before full deployment
## Tools integration
This guide covers integration with:
- Okta
- Entra ID SAML 2.0
- Azure Connect (OIDC)
- MDM solutions like Intune

View File

@@ -1,75 +0,0 @@
---
title: Communication and information gathering
description: Gather your company's requirements from key stakeholders and communicate to your developers.
keywords: admin, onboarding, stakeholders, communication, mdm, requirements
weight: 10
---
## Communicate with your developers and IT teams
Before rolling out Docker Desktop across your organization, coordinate with key stakeholders to ensure a smooth transition.
### Notify Docker Desktop users
You may already have Docker Desktop users within your company. Some steps in
this onboarding process may affect how they interact with the platform.
Communicate early with users to inform them that:
- They'll be upgraded to a supported version of Docker Desktop as part of the subscription onboarding
- Settings will be reviewed and optimized for productivity
- They'll need to sign in to the company's Docker organization using their
business email to access subscription benefits
### Engage with your MDM team
Device management solutions, such as Intune and Jamf, are commonly used for
software distribution across enterprises. These tools are typically managed by a dedicated MDM team.
Engage with this team early in the process to:
- Understand their requirements and lead time for deploying changes
- Coordinate the distribution of configuration files
Several setup steps in this guide require JSON files, registry keys, or .plist
files to be distributed to developer machines. Use MDM tools to deploy these configuration files and ensure their integrity.
## Identify Docker organizations
Some companies may have more than one
[Docker organization](/manuals/admin/organization/_index.md) created. These
organizations may have been created for specific purposes, or may not be
needed anymore.
If you suspect your company has multiple Docker organizations:
- Survey your teams to see if they have their own organizations
- Contact your Docker Support to get a list of organizations with users whose
emails match your domain name
## Gather requirements
[Settings Management](/manuals/enterprise/security/hardened-desktop/settings-management/_index.md) lets you preset numerous configuration parameters for Docker Desktop.
Work with the following stakeholders to establish your company's baseline
configuration:
- Docker organization owner
- Development lead
- Information security representative
Review these areas together:
- Security features and
[enforcing sign-in](/manuals/enterprise/security/enforce-sign-in/_index.md)
for Docker Desktop users
- Additional Docker products included in your subscriptions
To view the parameters that can be preset, see [Configure Settings Management](/manuals/enterprise/security/hardened-desktop/settings-management/configure-json-file.md#step-two-configure-the-settings-you-want-to-lock-in).
## Optional: Meet with the Docker Implementation team
The Docker Implementation team can help you set up your organization,
configure SSO, enforce sign-in, and configure Docker Desktop.
To schedule a meeting, email successteam@docker.com.

View File

@@ -1,36 +0,0 @@
---
title: Deploy your Docker setup
description: Deploy your Docker setup across your company.
keywords: admin, onboarding, deployment, sso, rollout, organization
weight: 40
---
> [!WARNING]
>
> Communicate with your users before proceeding, and confirm that your IT and
> MDM teams are prepared to handle any unexpected issues, as these steps will
> affect all existing users signing into your Docker organization.
## Enforce SSO
Enforcing SSO means that anyone who has a Docker profile with an email address
that matches your verified domain must sign in using your SSO connection. Make
sure the Identity provider groups associated with your SSO connection cover all
the developer groups that you want to have access to the Docker subscription.
For instructions on how to enforce SSO, see [Enforce SSO](/manuals/enterprise/security/single-sign-on/connect.md).
## Deploy configuration settings and enforce sign-in to users
Have the MDM team deploy the configuration files for Docker to all users.
## Next steps
Congratulations, you've successfully completed the admin implementation process
for Docker.
To continue optimizing your Docker environment:
- Review your [organization's usage data](/manuals/admin/insights.md) to track adoption
- Monitor [Docker Scout findings](/manuals/scout/explore/analysis.md) for security insights
- Explore [additional security features](/manuals/enterprise/security/_index.md) to enhance your configuration

View File

@@ -1,77 +0,0 @@
---
title: Finalize plans and begin setup
description: Collaborate with your MDM team to distribute configurations and set up SSO and Docker product trials.
keywords: admin, onboarding, mdm, settings management, sso, configuration
weight: 20
---
## Send finalized settings files to the MDM team
After reaching an agreement with the relevant teams about your baseline and
security configurations as outlined in the previous section, configure Settings Management using either the [Docker Admin Console](/manuals/enterprise/security/hardened-desktop/settings-management/configure-admin-console.md) or an
[`admin-settings.json` file](/manuals/enterprise/security/hardened-desktop/settings-management/configure-json-file.md).
Once the file is ready, collaborate with your MDM team to deploy your chosen
settings, along with your chosen method for [enforcing sign-in](/manuals/enterprise/security/enforce-sign-in/_index.md).
> [!IMPORTANT]
>
> Test this first with a small number of Docker Desktop developers to verify the functionality works as expected before deploying more widely.
## Manage your organizations
If you have more than one organization, consider either [consolidating them
into one organization](/manuals/admin/organization/setup/orgs.md) or creating a
[Docker company](/manuals/admin/company/_index.md) to manage multiple
organizations.
## Begin setup
### Set up single sign-on and domain verification
Single sign-on (SSO) lets developers authenticate using their identity
providers (IdPs) to access Docker. SSO is available for a whole company and all associated organizations, or an individual organization that has a Docker
Business subscription. For more information, see the
[documentation](/manuals/enterprise/security/single-sign-on/_index.md).
You can also enable [SCIM](/manuals/enterprise/security/provisioning/scim/_index.md)
for further automation of provisioning and deprovisioning of users.
### Set up Docker product entitlements included in the subscription
[Docker Build Cloud](/manuals/build-cloud/_index.md) significantly reduces
build times, both locally and in CI, by providing a dedicated remote builder
and shared cache. Powered by the cloud, developer time and local resources are
freed up so your team can focus on more important things, like innovation.
To get started, [set up a cloud builder](https://app.docker.com/build/).
[Docker Scout](manuals/scout/_index.md) is a solution for proactively enhancing
your software supply chain security. By analyzing your images, Docker Scout
compiles an inventory of components, also known as a Software Bill of Materials
(SBOM). The SBOM is matched against a continuously updated vulnerability
database to pinpoint security weaknesses. To get started, see
[Quickstart](/manuals/scout/quickstart.md).
[Testcontainers Cloud](https://testcontainers.com/cloud/docs/) allows
developers to run containers in the cloud, removing the need to run heavy
containers on your local machine.
[Docker Hardened Images](/manuals/dhi/_index.md) are minimal, secure, and production-ready container base and application images maintained by Docker.
Designed to reduce vulnerabilities and simplify compliance, DHIs integrate
easily into your existing Docker-based workflows with little to no retooling
required.
### Ensure you're running a supported version of Docker Desktop
> [!WARNING]
>
> This step could affect the experience for users on older versions of Docker
> Desktop.
Existing users may be running outdated or unsupported versions of
Docker Desktop. All users should update to a supported version. Docker Desktop
versions released within the past 6 months from the latest release are supported.
Use an MDM solution to manage the version of Docker Desktop for users. Users
may also get Docker Desktop directly from Docker or through a company software
portal.

View File

@@ -0,0 +1,330 @@
---
title: Set up your company for success with Docker
linkTitle: Admin set up
summary: Get the most out of Docker by streamlining workflows, standardizing development environments, and ensuring smooth deployments across your company.
description: Learn how to onboard your company and take advantage of all of the Docker products and features.
keywords: admin, onboarding, deployment, organization setup, docker business, rollout
aliases:
- /guides/admin-set-up/comms-and-info-gathering/
- /guides/admin-set-up/deploy/
- /guides/admin-set-up/finalize-plans-and-setup/
- /guides/admin-set-up/testing/
params:
tags: [admin]
time: 20 minutes
image:
---
Docker's tools provide a scalable, secure platform that empowers your
developers to create, ship, and run applications faster. As an administrator,
you can streamline workflows, standardize development environments, and ensure
smooth deployments across your organization.
By configuring Docker products to suit your company's needs, you can optimize
performance, simplify user management, and maintain control over resources.
This guide helps you set up and configure Docker products to maximize
productivity and success for your team while meeting compliance and security
policies.
## Who’s this for?
- Administrators responsible for managing Docker environments within their
organization
- IT leaders looking to streamline development and deployment workflows
- Teams aiming to standardize application environments across multiple users
- Organizations seeking to optimize their use of Docker products for greater
scalability and efficiency
- Organizations with a
[Docker Business subscription](https://www.docker.com/pricing?ref=DocsGuides&refAction=DocsGuidesCTAClicked)
## What you’ll learn
- Why signing into your company's Docker organization provides access to usage
data and enhanced functionality
- How to standardize Docker Desktop versions and settings to create a consistent
baseline for all users, while allowing flexibility for advanced developers
- Strategies for implementing Docker's security configurations to meet company
IT and software development security requirements without hindering developer productivity
## Features covered
This guide covers the following Docker features:
- [Organizations](/manuals/admin/organization/_index.md): The core structure
for managing your Docker environment, grouping users, teams, and image
repositories. Your organization was created with your subscription and is
managed by one or more owners. Users signed into the organization are
assigned seats based on the purchased subscription.
- [Enforce sign-in](/manuals/enterprise/security/enforce-sign-in/_index.md):
By default, Docker Desktop doesn't require sign-in. You can configure
settings to enforce this and ensure your developers sign in to your
Docker organization.
- [SSO](/manuals/enterprise/security/single-sign-on/_index.md): Without SSO,
user management in a Docker organization is manual. Setting
up an SSO connection between your identity provider and Docker ensures
compliance with your security policy and automates user provisioning. Adding
SCIM further automates user provisioning and de-provisioning.
- General and security settings: Configuring key settings ensures smooth
onboarding and usage of Docker products within your environment. You can also
enable security features based on your company's specific security needs.
## Who needs to be involved
- Docker organization owner: Must be involved in the process and is required
for several key steps
- DNS team: Needed during the SSO setup to verify the company domain
- MDM team: Responsible for distributing Docker-specific configuration files to
developer machines
- Identity Provider team: Required for configuring the identity provider and
establishing the SSO connection during setup
- Development lead: A development lead with knowledge of Docker configurations
to help establish a baseline for developer settings
- IT team: An IT representative familiar with company desktop policies to
assist with aligning Docker configuration to those policies
- Infosec: A security team member with knowledge of company development
security policies to help configure security features
- Docker testers: A small group of developers to test the new settings and
configurations before full deployment
## Tools integration
This guide covers integration with:
- Okta
- Entra ID SAML 2.0
- Azure Connect (OIDC)
- MDM solutions like Intune
## Communication and information gathering
### Communicate with your developers and IT teams
Before rolling out Docker Desktop across your organization, coordinate with key stakeholders to ensure a smooth transition.
#### Notify Docker Desktop users
You may already have Docker Desktop users within your company. Some steps in
this onboarding process may affect how they interact with the platform.
Communicate early with users to inform them that:
- They'll be upgraded to a supported version of Docker Desktop as part of the subscription onboarding
- Settings will be reviewed and optimized for productivity
- They'll need to sign in to the company's Docker organization using their
business email to access subscription benefits
#### Engage with your MDM team
Device management solutions, such as Intune and Jamf, are commonly used for
software distribution across enterprises. These tools are typically managed by a dedicated MDM team.
Engage with this team early in the process to:
- Understand their requirements and lead time for deploying changes
- Coordinate the distribution of configuration files
Several setup steps in this guide require JSON files, registry keys, or .plist
files to be distributed to developer machines. Use MDM tools to deploy these configuration files and ensure their integrity.
### Identify Docker organizations
Some companies may have more than one
[Docker organization](/manuals/admin/organization/_index.md) created. These
organizations may have been created for specific purposes, or may not be
needed anymore.
If you suspect your company has multiple Docker organizations:
- Survey your teams to see if they have their own organizations
- Contact your Docker Support to get a list of organizations with users whose
emails match your domain name
### Gather requirements
[Settings Management](/manuals/enterprise/security/hardened-desktop/settings-management/_index.md) lets you preset numerous configuration parameters for Docker Desktop.
Work with the following stakeholders to establish your company's baseline
configuration:
- Docker organization owner
- Development lead
- Information security representative
Review these areas together:
- Security features and
[enforcing sign-in](/manuals/enterprise/security/enforce-sign-in/_index.md)
for Docker Desktop users
- Additional Docker products included in your subscriptions
To view the parameters that can be preset, see [Configure Settings Management](/manuals/enterprise/security/hardened-desktop/settings-management/configure-json-file.md#step-two-configure-the-settings-you-want-to-lock-in).
### Optional: Meet with the Docker Implementation team
The Docker Implementation team can help you set up your organization,
configure SSO, enforce sign-in, and configure Docker Desktop.
To schedule a meeting, email successteam@docker.com.
## Finalize plans and begin setup
### Send finalized settings files to the MDM team
After reaching an agreement with the relevant teams about your baseline and
security configurations as outlined in the previous section, configure Settings Management using either the [Docker Admin Console](/manuals/enterprise/security/hardened-desktop/settings-management/configure-admin-console.md) or an
[`admin-settings.json` file](/manuals/enterprise/security/hardened-desktop/settings-management/configure-json-file.md).
Once the file is ready, collaborate with your MDM team to deploy your chosen
settings, along with your chosen method for [enforcing sign-in](/manuals/enterprise/security/enforce-sign-in/_index.md).
> [!IMPORTANT]
>
> Test this first with a small number of Docker Desktop developers to verify the functionality works as expected before deploying more widely.
### Manage your organizations
If you have more than one organization, consider either [consolidating them
into one organization](/manuals/admin/organization/setup/orgs.md) or creating a
[Docker company](/manuals/admin/company/_index.md) to manage multiple
organizations.
### Begin setup
#### Set up single sign-on and domain verification
Single sign-on (SSO) lets developers authenticate using their identity
providers (IdPs) to access Docker. SSO is available for a whole company and all associated organizations, or an individual organization that has a Docker
Business subscription. For more information, see the
[documentation](/manuals/enterprise/security/single-sign-on/_index.md).
You can also enable [SCIM](/manuals/enterprise/security/provisioning/scim/_index.md)
for further automation of provisioning and deprovisioning of users.
#### Set up Docker product entitlements included in the subscription
[Docker Build Cloud](/manuals/build-cloud/_index.md) significantly reduces
build times, both locally and in CI, by providing a dedicated remote builder
and shared cache. Powered by the cloud, developer time and local resources are
freed up so your team can focus on more important things, like innovation.
To get started, [set up a cloud builder](https://app.docker.com/build/).
[Docker Scout](manuals/scout/_index.md) is a solution for proactively enhancing
your software supply chain security. By analyzing your images, Docker Scout
compiles an inventory of components, also known as a Software Bill of Materials
(SBOM). The SBOM is matched against a continuously updated vulnerability
database to pinpoint security weaknesses. To get started, see
[Quickstart](/manuals/scout/quickstart.md).
[Testcontainers Cloud](https://testcontainers.com/cloud/docs/) allows
developers to run containers in the cloud, removing the need to run heavy
containers on your local machine.
[Docker Hardened Images](/manuals/dhi/_index.md) are minimal, secure, and production-ready container base and application images maintained by Docker.
Designed to reduce vulnerabilities and simplify compliance, DHIs integrate
easily into your existing Docker-based workflows with little to no retooling
required.
#### Ensure you're running a supported version of Docker Desktop
> [!WARNING]
>
> This step could affect the experience for users on older versions of Docker
> Desktop.
Existing users may be running outdated or unsupported versions of
Docker Desktop. All users should update to a supported version. Docker Desktop
versions released within the past 6 months from the latest release are supported.
Use an MDM solution to manage the version of Docker Desktop for users. Users
may also get Docker Desktop directly from Docker or through a company software
portal.
## Testing
### SSO and SCIM testing
Test SSO and SCIM by signing in to Docker Desktop or Docker Hub with the email
address linked to a Docker account that is part of the verified domain.
Developers who sign in using their Docker usernames remain unaffected by the
SSO and SCIM setup.
> [!IMPORTANT]
>
> Some users may need CLI based logins to Docker Hub, and for this they will
> need a [personal access token (PAT)](/manuals/security/access-tokens.md).
### Test Registry Access Management and Image Access Management
> [!WARNING]
>
> Communicate with your users before proceeding, as this step will impact all
> existing users signing into your Docker organization.
If you plan to use [Registry Access Management (RAM)](/manuals/enterprise/security/hardened-desktop/registry-access-management.md) and/or [Image Access Management (IAM)](/manuals/enterprise/security/hardened-desktop/image-access-management.md):
1. Ensure your test developer signs in to Docker Desktop using their
organization credentials
2. Have them attempt to pull an unauthorized image or one from a disallowed
registry via the Docker CLI
3. Verify they receive an error message indicating that the registry is
restricted by the organization
### Deploy settings and enforce sign in to test group
Deploy the Docker settings and enforce sign-in for a small group of test users
via MDM. Have this group test their development workflows with containers on
Docker Desktop and Docker Hub to ensure all settings and the sign-in enforcement
function as expected.
### Test Docker Build Cloud capabilities
Have one of your Docker Desktop testers [connect to the cloud builder you created and use it to build](/manuals/build-cloud/usage.md).
### Test Testcontainers Cloud
Have a test developer [connect to Testcontainers Cloud](https://testcontainers.com/cloud/docs/#getting-started) and run a container in
the cloud to verify the setup is working correctly.
### Verify Docker Scout monitoring of repositories
Check the [Docker Scout dashboard](https://scout.docker.com/) to confirm that
data is being properly received for the repositories where Docker Scout has
been enabled.
### Verify access to Docker Hardened Images
Have a test developer attempt to [pull a Docker Hardened Image](/manuals/dhi/get-started.md) to confirm that
the team has proper access and can integrate these images into their workflows.
## Deploy your Docker setup
> [!WARNING]
>
> Communicate with your users before proceeding, and confirm that your IT and
> MDM teams are prepared to handle any unexpected issues, as these steps will
> affect all existing users signing into your Docker organization.
### Enforce SSO
Enforcing SSO means that anyone who has a Docker profile with an email address
that matches your verified domain must sign in using your SSO connection. Make
sure the Identity provider groups associated with your SSO connection cover all
the developer groups that you want to have access to the Docker subscription.
For instructions on how to enforce SSO, see [Enforce SSO](/manuals/enterprise/security/single-sign-on/connect.md).
### Deploy configuration settings and enforce sign-in to users
Have the MDM team deploy the configuration files for Docker to all users.
### Next steps
Congratulations, you've successfully completed the admin implementation process
for Docker.
To continue optimizing your Docker environment:
- Review your [organization's usage data](/manuals/admin/insights.md) to track adoption
- Monitor [Docker Scout findings](/manuals/scout/explore/analysis.md) for security insights
- Explore [additional security features](/manuals/enterprise/security/_index.md) to enhance your configuration

View File

@@ -1,61 +0,0 @@
---
title: Testing
description: Test your Docker setup.
keywords: admin, onboarding, testing, sso, scim, verification
weight: 30
---
## SSO and SCIM testing
Test SSO and SCIM by signing in to Docker Desktop or Docker Hub with the email
address linked to a Docker account that is part of the verified domain.
Developers who sign in using their Docker usernames remain unaffected by the
SSO and SCIM setup.
> [!IMPORTANT]
>
> Some users may need CLI based logins to Docker Hub, and for this they will
> need a [personal access token (PAT)](/manuals/security/access-tokens.md).
## Test Registry Access Management and Image Access Management
> [!WARNING]
>
> Communicate with your users before proceeding, as this step will impact all
> existing users signing into your Docker organization.
If you plan to use [Registry Access Management (RAM)](/manuals/enterprise/security/hardened-desktop/registry-access-management.md) and/or [Image Access Management (IAM)](/manuals/enterprise/security/hardened-desktop/image-access-management.md):
1. Ensure your test developer signs in to Docker Desktop using their
organization credentials
2. Have them attempt to pull an unauthorized image or one from a disallowed
registry via the Docker CLI
3. Verify they receive an error message indicating that the registry is
restricted by the organization
## Deploy settings and enforce sign in to test group
Deploy the Docker settings and enforce sign-in for a small group of test users
via MDM. Have this group test their development workflows with containers on
Docker Desktop and Docker Hub to ensure all settings and the sign-in enforcement
function as expected.
## Test Docker Build Cloud capabilities
Have one of your Docker Desktop testers [connect to the cloud builder you created and use it to build](/manuals/build-cloud/usage.md).
## Test Testcontainers Cloud
Have a test developer [connect to Testcontainers Cloud](https://testcontainers.com/cloud/docs/#getting-started) and run a container in
the cloud to verify the setup is working correctly.
## Verify Docker Scout monitoring of repositories
Check the [Docker Scout dashboard](https://scout.docker.com/) to confirm that
data is being properly received for the repositories where Docker Scout has
been enabled.
## Verify access to Docker Hardened Images
Have a test developer attempt to [pull a Docker Hardened Image](/manuals/dhi/get-started.md) to confirm that
the team has proper access and can integrate these images into their workflows.

View File

@@ -1,47 +0,0 @@
---
title: Mastering user and access management
summary: Simplify user access while ensuring security and efficiency in Docker.
description: A guide for managing roles, provisioning users, and optimizing Docker access with tools like SSO and activity logs.
keywords: admin, user management, roles, permissions, sso, provisioning, access control
tags: [admin]
params:
featured: false
time: 20 minutes
image:
resource_links:
- title: Overview of Administration in Docker
url: /admin/
- title: Single sign-on
url: /security/for-admins/single-sign-on/
- title: Onboard your organization
url: /admin/organization/setup/onboard/
- title: Roles and permissions
url: /security/for-admins/roles-and-permissions/
- title: Insights
url: /admin/insights/
- title: Activity logs
url: /admin/activity-logs/
---
Managing roles and permissions is key to securing your Docker environment while enabling easy collaboration and operational efficiency. This guide walks IT administrators through the essentials of user and access management, offering strategies for assigning roles, provisioning users, and using tools like activity logs and Insights to monitor and optimize Docker usage.
## Who's this for?
- IT teams tasked with configuring and maintaining secure user access
- Security professionals focused on enforcing secure access practices
- Project managers overseeing team collaboration and resource management
## What you'll learn
- How to assess and manage Docker user access and align accounts with organizational needs
- When to use team configurations for scalable access control
- How to automate and streamline user provisioning with SSO, SCIM, and JIT
- How to get the most out of Docker's monitoring tools
## Tools integration
This guide covers integration with:
- Okta
- Entra ID SAML 2.0
- Azure Connect (OIDC)

View File

@@ -1,54 +0,0 @@
---
title: Monitoring and insights
description: Track user actions, team workflows, and organizational trends with Activity logs and Insights to enhance security and productivity in Docker.
keywords: organizational insights, user management, access control, security, monitoring, admins
weight: 30
---
Activity logs and Insights are useful tools for user and access management in Docker. They provide visibility into user actions, team workflows, and organizational trends, helping enhance security, ensure compliance, and boost productivity.
## Activity logs
Activity logs track events at the organization and repository levels, offering a clear view of activities like repository changes, team updates, and billing adjustments.
Activity logs are available for Docker Team or Docker Business plans, with data retained for three months.
### Key features
- Change tracking: View what changed, who made the change, and when.
- Comprehensive reporting: Monitor critical events such as repository creation, deletion, privacy changes, and role assignments.
### Example scenarios
- Audit trail for security: A repository’s privacy settings were updated unexpectedly. The activity logs reveal which user made the change and when, helping administrators address potential security risks.
- Team collaboration review: Logs show which team members pushed updates to a critical repository, ensuring accountability during a development sprint.
- Billing adjustments: Track who added or removed subscription seats to maintain budgetary control and compliance.
For more information, see [Activity logs](/manuals/admin/activity-logs.md).
## Insights
Insights provide data-driven views of Docker usage to improve team productivity and resource allocation.
### Key benefits
- Standardized environments: Ensure consistent configurations and enforce best practices across teams.
- Improved visibility: Monitor metrics like Docker Desktop usage, builds, and container activity to understand team workflows and engagement.
- Optimized resources: Track license usage and feature adoption to maximize the value of your Docker subscription.
### Example scenarios
- Usage trends: Identify underutilized licenses or resources, allowing reallocation to more active teams.
- Build efficiency: Track average build times and success rates to pinpoint bottlenecks in development processes.
- Container utilization: Analyze container activity across departments to ensure proper resource distribution and cost efficiency.
For more information, see [Insights](/manuals/admin/insights.md).
## Next steps
Now that you've mastered user and access management in Docker, you can:
- Review your [activity logs](/manuals/admin/activity-logs.md) regularly to maintain security awareness
- Check your [Insights dashboard](/manuals/admin/insights.md) to identify opportunities for optimization
- Explore [advanced security features](/manuals/enterprise/security/_index.md) to further enhance your Docker environment
- Share best practices with your team to ensure consistent adoption of security policies

View File

@@ -0,0 +1,198 @@
---
title: Mastering user and access management
summary: Simplify user access while ensuring security and efficiency in Docker.
description: A guide for managing roles, provisioning users, and optimizing Docker access with tools like SSO and activity logs.
keywords: admin, user management, roles, permissions, sso, provisioning, access control
aliases:
- /guides/admin-user-management/audit-and-monitor/
- /guides/admin-user-management/onboard/
- /guides/admin-user-management/setup/
params:
tags: [admin]
featured: false
time: 20 minutes
image:
---
Managing roles and permissions is key to securing your Docker environment while enabling easy collaboration and operational efficiency. This guide walks IT administrators through the essentials of user and access management, offering strategies for assigning roles, provisioning users, and using tools like activity logs and Insights to monitor and optimize Docker usage.
## Who's this for?
- IT teams tasked with configuring and maintaining secure user access
- Security professionals focused on enforcing secure access practices
- Project managers overseeing team collaboration and resource management
## What you'll learn
- How to assess and manage Docker user access and align accounts with organizational needs
- When to use team configurations for scalable access control
- How to automate and streamline user provisioning with SSO, SCIM, and JIT
- How to get the most out of Docker's monitoring tools
## Tools integration
This guide covers integration with:
- Okta
- Entra ID SAML 2.0
- Azure Connect (OIDC)
## Setting up roles and permissions in Docker
With the right configurations, you can ensure your developers have easy access to necessary resources while preventing unauthorized access. This page guides you through identifying Docker users so you can allocate subscription seats efficiently within your Docker organization, and assigning roles to align with your organization's structure.
### Identify your Docker users and accounts
Before setting up roles and permissions, it's important to have a clear understanding of who in your organization requires Docker access. Focus on gathering a comprehensive view of active users, their roles within projects, and how they interact with Docker resources. This process can be supported by tools like device management software or manual assessments. Encourage all users to update their Docker accounts to use organizational email addresses, ensuring seamless integration with your subscription.
For steps on how you can do this, see [step 1 of onboarding your organization](/manuals/admin/organization/setup/onboard.md).
### Assign roles strategically
When you invite members to join your Docker organization, you assign them a role.
Docker's predefined roles offer flexibility for various organizational needs. Assigning roles effectively ensures a balance of accessibility and security.
- Member: Non-administrative role. Members can view other members that are in the same organization.
- Editor: Partial administrative access to the organization. Editors can create, edit, and delete repositories. They can also edit an existing team's access permissions.
- Owner: Full organization administrative access. Owners can manage organization repositories, teams, members, settings, and billing.
For more information, see [Roles and permissions](/manuals/enterprise/security/roles-and-permissions.md).
#### Enhance with teams
Teams in Docker provide a structured way to manage member access and they provide an additional level of permissions. They simplify permission management and enable consistent application of policies.
- Organize users into teams aligned with projects, departments, or functional roles. This approach helps streamline resource allocation and ensures clarity in access control.
- Assign permissions at the team level rather than individually. For instance, a development team might have "Read & Write" access to certain repositories, while a QA team has "Read-only" access.
- As teams grow or responsibilities shift, you can easily update permissions or add new members, maintaining consistency without reconfiguring individual settings.
For more information, see [Create and manage a team](/manuals/admin/organization/manage/manage-a-team.md).
#### Example scenarios
- Development teams: Assign the member role to developers, granting access to the repositories needed for coding and testing.
- Team leads: Assign the editor role to team leads for resource management and repository control within their teams.
- Organizational oversight: Restrict the organization owner or company owner roles to a select few trusted individuals responsible for billing and security settings.
#### Best practices
- Apply the principle of least privilege. Assign users only the minimum permissions necessary for their roles.
- Conduct regular reviews of role assignments to ensure they align with evolving team structures and organizational responsibilities.
## Onboarding and managing roles and permissions in Docker
This page guides you through onboarding owners and members, and using tools like SSO and SCIM to future-proof onboarding going forward.
### Invite owners
When you create a Docker organization, you automatically become its sole owner. While optional, adding additional owners can significantly ease the process of onboarding and managing your organization by distributing administrative responsibilities. It also ensures continuity and prevents blockers if the primary owner is unavailable.
For detailed information on owners, see [Roles and permissions](/manuals/enterprise/security/roles-and-permissions.md).
### Invite members and assign roles
Members are granted controlled access to resources and enjoy enhanced organizational benefits. When you invite members to join your Docker organization, you immediately assign them a role.
#### Benefits of inviting members
- Enhanced visibility: Gain insights into user activity, making it easier to monitor access and enforce security policies.
- Streamlined collaboration: Help members collaborate effectively by granting access to shared resources and repositories.
- Improved resource management: Organize and track users within your organization, ensuring optimal allocation of resources.
- Access to enhanced features: Members benefit from organization-wide perks, such as increased pull limits and access to premium Docker features.
- Security control: Apply and enforce security settings at an organizational level, reducing risks associated with unmanaged accounts.
For detailed information, see [Manage organization members](/manuals/admin/organization/manage/members.md).
### Future-proof user management
A robust, future-proof approach to user management combines automated provisioning, centralized authentication, and dynamic access control. Implementing these practices ensures a scalable, secure, and efficient environment.
#### Secure user authentication with single sign-on (SSO)
Integrating Docker with your identity provider streamlines user access and enhances security.
SSO:
- Simplifies sign in, as users sign in with their organizational credentials.
- Reduces password-related vulnerabilities.
- Simplifies onboarding as it works seamlessly with SCIM and group mapping for automated provisioning.
For more information, see the [SSO documentation](/manuals/enterprise/security/single-sign-on/_index.md).
#### Automate onboarding with SCIM and JIT provisioning
Streamline user provisioning and role management with [SCIM](/manuals/enterprise/security/provisioning/scim/_index.md) and [Just-in-Time (JIT) provisioning](/manuals/enterprise/security/provisioning/just-in-time.md).
With SCIM you can:
- Sync users and roles automatically with your identity provider.
- Automate adding, updating, or removing users based on directory changes.
With JIT provisioning you can:
- Automatically add users upon first sign in based on [group mapping](#simplify-access-with-group-mapping).
- Reduce overhead by eliminating pre-invite steps.
#### Simplify access with group mapping
Group mapping automates permissions management by linking identity provider groups to Docker roles and teams.
It also:
- Reduces manual errors in role assignments.
- Ensures consistent access control policies.
- Help you scale permissions as teams grow or change.
For more information on how it works, see [Group mapping](/manuals/enterprise/security/provisioning/scim/group-mapping.md).
## Monitoring and insights
Activity logs and Insights are useful tools for user and access management in Docker. They provide visibility into user actions, team workflows, and organizational trends, helping enhance security, ensure compliance, and boost productivity.
### Activity logs
Activity logs track events at the organization and repository levels, offering a clear view of activities like repository changes, team updates, and billing adjustments.
Activity logs are available for Docker Team or Docker Business plans, with data retained for three months.
#### Key features
- Change tracking: View what changed, who made the change, and when.
- Comprehensive reporting: Monitor critical events such as repository creation, deletion, privacy changes, and role assignments.
#### Example scenarios
- Audit trail for security: A repository’s privacy settings were updated unexpectedly. The activity logs reveal which user made the change and when, helping administrators address potential security risks.
- Team collaboration review: Logs show which team members pushed updates to a critical repository, ensuring accountability during a development sprint.
- Billing adjustments: Track who added or removed subscription seats to maintain budgetary control and compliance.
For more information, see [Activity logs](/manuals/admin/activity-logs.md).
### Insights
Insights provide data-driven views of Docker usage to improve team productivity and resource allocation.
#### Key benefits
- Standardized environments: Ensure consistent configurations and enforce best practices across teams.
- Improved visibility: Monitor metrics like Docker Desktop usage, builds, and container activity to understand team workflows and engagement.
- Optimized resources: Track license usage and feature adoption to maximize the value of your Docker subscription.
#### Example scenarios
- Usage trends: Identify underutilized licenses or resources, allowing reallocation to more active teams.
- Build efficiency: Track average build times and success rates to pinpoint bottlenecks in development processes.
- Container utilization: Analyze container activity across departments to ensure proper resource distribution and cost efficiency.
For more information, see [Insights](/manuals/admin/insights.md).
### Next steps
Now that you've mastered user and access management in Docker, you can:
- Review your [activity logs](/manuals/admin/activity-logs.md) regularly to maintain security awareness
- Check your [Insights dashboard](/manuals/admin/insights.md) to identify opportunities for optimization
- Explore [advanced security features](/manuals/enterprise/security/_index.md) to further enhance your Docker environment
- Share best practices with your team to ensure consistent adoption of security policies

View File

@@ -1,70 +0,0 @@
---
title: Onboarding and managing roles and permissions in Docker
description: Learn how to manage roles, invite members, and implement scalable access control in Docker for secure and efficient collaboration.
keywords: sso, scim, jit, invite members, docker hub, docker admin console, onboarding, security
weight: 20
---
This page guides you through onboarding owners and members, and using tools like SSO and SCIM to future-proof onboarding going forward.
## Invite owners
When you create a Docker organization, you automatically become its sole owner. While optional, adding additional owners can significantly ease the process of onboarding and managing your organization by distributing administrative responsibilities. It also ensures continuity and prevents blockers if the primary owner is unavailable.
For detailed information on owners, see [Roles and permissions](/manuals/enterprise/security/roles-and-permissions.md).
## Invite members and assign roles
Members are granted controlled access to resources and enjoy enhanced organizational benefits. When you invite members to join your Docker organization, you immediately assign them a role.
### Benefits of inviting members
- Enhanced visibility: Gain insights into user activity, making it easier to monitor access and enforce security policies.
- Streamlined collaboration: Help members collaborate effectively by granting access to shared resources and repositories.
- Improved resource management: Organize and track users within your organization, ensuring optimal allocation of resources.
- Access to enhanced features: Members benefit from organization-wide perks, such as increased pull limits and access to premium Docker features.
- Security control: Apply and enforce security settings at an organizational level, reducing risks associated with unmanaged accounts.
For detailed information, see [Manage organization members](/manuals/admin/organization/manage/members.md).
## Future-proof user management
A robust, future-proof approach to user management combines automated provisioning, centralized authentication, and dynamic access control. Implementing these practices ensures a scalable, secure, and efficient environment.
### Secure user authentication with single sign-on (SSO)
Integrating Docker with your identity provider streamlines user access and enhances security.
SSO:
- Simplifies sign in, as users sign in with their organizational credentials.
- Reduces password-related vulnerabilities.
- Simplifies onboarding as it works seamlessly with SCIM and group mapping for automated provisioning.
For more information, see the [SSO documentation](/manuals/enterprise/security/single-sign-on/_index.md).
### Automate onboarding with SCIM and JIT provisioning
Streamline user provisioning and role management with [SCIM](/manuals/enterprise/security/provisioning/scim/_index.md) and [Just-in-Time (JIT) provisioning](/manuals/enterprise/security/provisioning/just-in-time.md).
With SCIM you can:
- Sync users and roles automatically with your identity provider.
- Automate adding, updating, or removing users based on directory changes.
With JIT provisioning you can:
- Automatically add users upon first sign in based on [group mapping](#simplify-access-with-group-mapping).
- Reduce overhead by eliminating pre-invite steps.
### Simplify access with group mapping
Group mapping automates permissions management by linking identity provider groups to Docker roles and teams.
It also:
- Reduces manual errors in role assignments.
- Ensures consistent access control policies.
- Help you scale permissions as teams grow or change.
For more information on how it works, see [Group mapping](/manuals/enterprise/security/provisioning/scim/group-mapping.md).

View File

@@ -1,47 +0,0 @@
---
title: Setting up roles and permissions in Docker
description: A guide to securely managing access and collaboration in Docker through roles and teams.
keywords: Docker roles, permissions management, access control, IT administration, team collaboration, least privilege, security, Docker Teams, role-based access
weight: 10
---
With the right configurations, you can ensure your developers have easy access to necessary resources while preventing unauthorized access. This page guides you through identifying Docker users so you can allocate subscription seats efficiently within your Docker organization, and assigning roles to align with your organization's structure.
## Identify your Docker users and accounts
Before setting up roles and permissions, it's important to have a clear understanding of who in your organization requires Docker access. Focus on gathering a comprehensive view of active users, their roles within projects, and how they interact with Docker resources. This process can be supported by tools like device management software or manual assessments. Encourage all users to update their Docker accounts to use organizational email addresses, ensuring seamless integration with your subscription.
For steps on how you can do this, see [step 1 of onboarding your organization](/manuals/admin/organization/setup/onboard.md).
## Assign roles strategically
When you invite members to join your Docker organization, you assign them a role.
Docker's predefined roles offer flexibility for various organizational needs. Assigning roles effectively ensures a balance of accessibility and security.
- Member: Non-administrative role. Members can view other members that are in the same organization.
- Editor: Partial administrative access to the organization. Editors can create, edit, and delete repositories. They can also edit an existing team's access permissions.
- Owner: Full organization administrative access. Owners can manage organization repositories, teams, members, settings, and billing.
For more information, see [Roles and permissions](/manuals/enterprise/security/roles-and-permissions.md).
### Enhance with teams
Teams in Docker provide a structured way to manage member access and they provide an additional level of permissions. They simplify permission management and enable consistent application of policies.
- Organize users into teams aligned with projects, departments, or functional roles. This approach helps streamline resource allocation and ensures clarity in access control.
- Assign permissions at the team level rather than individually. For instance, a development team might have "Read & Write" access to certain repositories, while a QA team has "Read-only" access.
- As teams grow or responsibilities shift, you can easily update permissions or add new members, maintaining consistency without reconfiguring individual settings.
For more information, see [Create and manage a team](/manuals/admin/organization/manage/manage-a-team.md).
### Example scenarios
- Development teams: Assign the member role to developers, granting access to the repositories needed for coding and testing.
- Team leads: Assign the editor role to team leads for resource management and repository control within their teams.
- Organizational oversight: Restrict the organization owner or company owner roles to a select few trusted individuals responsible for billing and security settings.
### Best practices
- Apply the principle of least privilege. Assign users only the minimum permissions necessary for their roles.
- Conduct regular reviews of role assignments to ensure they align with evolving team structures and organizational responsibilities.

View File

@@ -5,7 +5,7 @@ keywords: AI, Docker, Model Runner, MCP Toolkit, AI agents, application developm
summary: |
Learn how to create AI agent applications using Docker Model Runner, and MCP Toolkit.
params:
tags: [AI]
tags: [ai]
time: 30 minutes
---

View File

@@ -1,50 +0,0 @@
---
title: Angular language-specific guide
linkTitle: Angular
description: Containerize and develop Angular apps using Docker
keywords: getting started, angular, docker, language, Dockerfile
summary: |
This guide explains how to containerize Angular applications using Docker.
toc_min: 1
toc_max: 2
aliases:
- /guides/angular/configure-github-actions/
- /guides/angular/deploy/
languages: [js]
params:
time: 20 minutes
---
The Angular language-specific guide shows you how to containerize an Angular application using Docker, following best practices for creating efficient, production-ready containers.
[Angular](https://angular.dev/) is a robust and widely adopted framework for building dynamic, enterprise-grade web applications. However, managing dependencies, environments, and deployments can become complex as applications scale. Docker streamlines these challenges by offering a consistent, isolated environment for development and production.
>
> **Acknowledgment**
>
> Docker extends its sincere gratitude to [Kristiyan Velkov](https://www.linkedin.com/in/kristiyan-velkov-763130b3/) for authoring this guide. As a Docker Captain and experienced Front-end engineer, his expertise in Docker, DevOps, and modern web development has made this resource essential for the community, helping developers navigate and optimize their Docker workflows.
---
## What will you learn?
In this guide, you will learn how to:
- Containerize and run an Angular application using Docker.
- Set up a local development environment for Angular inside a container.
- Run tests for your Angular application within a Docker container.
You'll start by containerizing an existing Angular application.
---
## Prerequisites
Before you begin, ensure you have a working knowledge of:
- Basic understanding of [TypeScript](https://www.typescriptlang.org/) and [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript).
- Familiarity with [Node.js](https://nodejs.org/en) and [npm](https://docs.npmjs.com/about-npm) for managing dependencies and running scripts.
- Familiarity with [Angular](https://angular.io/) fundamentals.
- Understanding of core Docker concepts such as images, containers, and Dockerfiles. If you're new to Docker, start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
Once you've completed the Angular getting started modules, you’ll be fully prepared to containerize your own Angular application using the detailed examples and best practices outlined in this guide.

View File

@@ -1,178 +0,0 @@
---
title: Use containers for Angular development
linkTitle: Develop your app
weight: 30
keywords: angular, development, node
description: Learn how to develop your Angular application locally using containers.
---
## Prerequisites
Complete [Containerize Angular application](containerize.md).
---
## Overview
In this section, you'll learn how to set up both production and development environments for your containerized Angular application using Docker Compose. This setup allows you to serve a static production build via Nginx and to develop efficiently inside containers using a live-reloading dev server with Compose Watch.
You’ll learn how to:
- Configure separate containers for production and development
- Enable automatic file syncing using Compose Watch in development
- Debug and live-preview your changes in real-time without manual rebuilds
---
## Automatically update services (development mode)
Use Compose Watch to automatically sync source file changes into your containerized development environment. This provides a seamless, efficient development experience without restarting or rebuilding containers manually.
## Step 1: Create a development Dockerfile
Create a file named `Dockerfile.dev` in your project root with the following content:
```dockerfile
# =========================================
# Stage 1: Development - Angular Application
# =========================================
# Define the Node.js version to use (Alpine for a small footprint)
ARG NODE_VERSION=24.12.0-alpine
# Set the base image for development
FROM node:${NODE_VERSION} AS dev
# Set environment variable to indicate development mode
ENV NODE_ENV=development
# Set the working directory inside the container
WORKDIR /app
# Copy only the dependency files first to optimize Docker caching
COPY package.json package-lock.json* ./
# Install dependencies using npm with caching to speed up subsequent builds
RUN --mount=type=cache,target=/root/.npm npm install
# Copy all application source files into the container
COPY . .
# Expose the port Angular uses for the dev server (default is 4200)
EXPOSE 4200
# Start the Angular dev server and bind it to all network interfaces
CMD ["npm", "start", "--", "--host=0.0.0.0"]
```
This file sets up a lightweight development environment for your Angular application using the dev server.
### Step 2: Update your `compose.yaml` file
Open your `compose.yaml` file and define two services: one for production (`angular-prod`) and one for development (`angular-dev`).
Here’s an example configuration for an Angular application:
```yaml
services:
angular-prod:
build:
context: .
dockerfile: Dockerfile
image: docker-angular-sample
ports:
- "8080:8080"
angular-dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "4200:4200"
develop:
watch:
- action: sync
path: .
target: /app
```
- The `angular-prod` service builds and serves your static production app using Nginx.
- The `angular-dev` service runs your Angular development server with live reload and hot module replacement.
- `watch` triggers file sync with Compose Watch.
> [!NOTE]
> For more details, see the official guide: [Use Compose Watch](/manuals/compose/how-tos/file-watch.md).
After completing the previous steps, your project directory should now contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ ├── .dockerignore
│ ├── compose.yaml
│ └── nginx.conf
```
### Step 4: Start Compose Watch
Run the following command from the project root to start the container in watch mode
```console
$ docker compose watch angular-dev
```
### Step 5: Test Compose Watch with Angular
To verify that Compose Watch is working correctly:
1. Open the `src/app/app.component.html` file in your text editor.
2. Locate the following line:
```html
<h1>Docker Angular Sample Application</h1>
```
3. Change it to:
```html
<h1>Hello from Docker Compose Watch</h1>
```
4. Save the file.
5. Open your browser at [http://localhost:4200](http://localhost:4200).
You should see the updated text appear instantly, without needing to rebuild the container manually. This confirms that file watching and automatic synchronization are working as expected.
---
## Summary
In this section, you set up a complete development and production workflow for your Angular application using Docker and Docker Compose.
Here’s what you accomplished:
- Created a `Dockerfile.dev` to streamline local development with hot reloading
- Defined separate `angular-dev` and `angular-prod` services in your `compose.yaml` file
- Enabled real-time file syncing using Compose Watch for a smoother development experience
- Verified that live updates work seamlessly by modifying and previewing a component
With this setup, you're now equipped to build, run, and iterate on your Angular app entirely within containers—efficiently and consistently across environments.
---
## Related resources
Deepen your knowledge and improve your containerized development workflow with these guides:
- [Using Compose Watch](/manuals/compose/how-tos/file-watch.md) – Automatically sync source changes during development
- [Multi-stage builds](/manuals/build/building/multi-stage.md) – Create efficient, production-ready Docker images
- [Dockerfile best practices](/build/building/best-practices/) – Write clean, secure, and optimized Dockerfiles.
- [Compose file reference](/compose/compose-file/) – Learn the full syntax and options available for configuring services in `compose.yaml`.
- [Docker volumes](/storage/volumes/) – Persist and manage data between container runs
## Next steps
In the next section, you'll learn how to run unit tests for your Angular application inside Docker containers. This ensures consistent testing across all environments and removes dependencies on local machine setup.

View File

@@ -1,14 +1,58 @@
---
title: Containerize an Angular Application
linkTitle: Containerize
weight: 10
keywords: angular, node, image, initialize, build
description: Learn how to containerize an Angular application with Docker by creating an optimized, production-ready image using best practices for performance, security, and scalability.
title: Angular language-specific guide
linkTitle: Angular
description: Containerize and develop Angular apps using Docker
keywords: getting started, angular, docker, language, Dockerfile
summary: |
This guide explains how to containerize Angular applications using Docker.
aliases:
- /guides/angular/configure-github-actions/
- /guides/angular/containerize/
- /guides/angular/deploy/
- /guides/angular/develop/
- /guides/angular/run-tests/
params:
tags: [languages]
time: 20 minutes
---
The Angular language-specific guide shows you how to containerize an Angular application using Docker, following best practices for creating efficient, production-ready containers.
[Angular](https://angular.dev/) is a robust and widely adopted framework for building dynamic, enterprise-grade web applications. However, managing dependencies, environments, and deployments can become complex as applications scale. Docker streamlines these challenges by offering a consistent, isolated environment for development and production.
> **Acknowledgment**
>
> Docker extends its sincere gratitude to [Kristiyan Velkov](https://www.linkedin.com/in/kristiyan-velkov-763130b3/) for authoring this guide. As a Docker Captain and experienced Front-end engineer, his expertise in Docker, DevOps, and modern web development has made this resource essential for the community, helping developers navigate and optimize their Docker workflows.
---
## What will you learn?
In this guide, you will learn how to:
- Containerize and run an Angular application using Docker.
- Set up a local development environment for Angular inside a container.
- Run tests for your Angular application within a Docker container.
You'll start by containerizing an existing Angular application and work your way up to production-level deployments.
---
## Prerequisites
Before you begin, ensure you have a working knowledge of:
- Basic understanding of [TypeScript](https://www.typescriptlang.org/) and [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript).
- Familiarity with [Node.js](https://nodejs.org/en) and [npm](https://docs.npmjs.com/about-npm) for managing dependencies and running scripts.
- Familiarity with [Angular](https://angular.io/) fundamentals.
- Understanding of core Docker concepts such as images, containers, and Dockerfiles. If you're new to Docker, start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
Once you've completed the Angular getting started modules, you’ll be fully prepared to containerize your own Angular application using the detailed examples and best practices outlined in this guide.
## Containerize an Angular Application
### Prerequisites
Before you begin, make sure the following tools are installed and available on your system:
- You have installed the latest version of [Docker Desktop](/get-started/get-docker.md).
@@ -19,21 +63,21 @@ Before you begin, make sure the following tools are installed and available on y
---
## Overview
### Overview
This guide walks you through the complete process of containerizing an Angular application with Docker. You’ll learn how to create a production-ready Docker image using best practices that improve performance, security, scalability, and deployment efficiency.
By the end of this guide, you will:
- Containerize an Angular application using Docker.
- Create and optimize a Dockerfile for production builds.
- Create and optimize a Dockerfile for production builds.
- Use multi-stage builds to minimize image size.
- Serve the application efficiently with a custom Nginx configuration.
- Build secure and maintainable Docker images by following best practices.
---
## Get the sample application
### Get the sample application
Clone the sample application to use with this guide. Open a terminal, navigate to the directory where you want to work, and run the following command
to clone the git repository:
@@ -41,9 +85,10 @@ to clone the git repository:
```console
$ git clone https://github.com/kristiyan-velkov/docker-angular-sample
```
---
## Build the Docker image
### Build the Docker image
Angular is a front-end framework that compiles into static assets, so the Dockerfile uses a multi-stage build: one stage compiles the app with Node.js, and a second minimal stage serves the static output with Nginx.
@@ -51,7 +96,7 @@ Angular is a front-end framework that compiles into static assets, so the Docker
>
> [Gordon](/ai/gordon/), Docker's AI assistant, can generate Docker assets for your project. Ask Gordon to create a Dockerfile, Compose file, and `.dockerignore` tailored to your application.
### Step 1: Create the Dockerfile
#### Step 1: Create the Dockerfile
Before creating a Dockerfile, you need to choose a base image. You can either use the [Node.js Official Image](https://hub.docker.com/_/node) or a Docker Hardened Image (DHI) from the [Hardened Image catalog](https://hub.docker.com/hardened-images/catalog).
@@ -67,6 +112,7 @@ Choosing DHI offers the advantage of a production-ready image that is lightweigh
Docker Hardened Images (DHIs) are available for Node.js in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/node). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
1. Sign in to the DHI registry:
```console
$ docker login dhi.io
```
@@ -99,7 +145,7 @@ RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
# Build the Angular application
RUN npm run build
RUN npm run build
# =========================================
# Stage 2: Prepare Nginx to Serve Static Files
@@ -117,7 +163,7 @@ COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/htm
USER nginx
# Expose port 8080 to allow HTTP traffic
# Note: The default Nginx container now listens on port 8080 instead of 80
# Note: The default Nginx container now listens on port 8080 instead of 80
EXPOSE 8080
# Start Nginx directly with custom config
@@ -153,7 +199,7 @@ RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
# Build the Angular application
RUN npm run build
RUN npm run build
# =========================================
# Stage 2: Prepare Nginx to Serve Static Files
@@ -171,7 +217,7 @@ COPY --chown=nginx:nginx --from=builder /app/dist/*/browser /usr/share/nginx/htm
USER nginx
# Expose port 8080 to allow HTTP traffic
# Note: The default Nginx container now listens on port 8080 instead of 80
# Note: The default Nginx container now listens on port 8080 instead of 80
EXPOSE 8080
# Start Nginx directly with custom config
@@ -182,14 +228,15 @@ CMD ["-g", "daemon off;"]
> [!NOTE]
> We are using nginx-unprivileged instead of the standard Nginx image to follow security best practices.
> Running as a non-root user in the final image:
>- Reduces the attack surface
>- Aligns with Docker’s recommendations for container hardening
>- Helps comply with stricter security policies in production environments
>
> - Reduces the attack surface
> - Aligns with Docker’s recommendations for container hardening
> - Helps comply with stricter security policies in production environments
{{< /tab >}}
{{< /tabs >}}
### Step 2: Create the compose.yaml file
#### Step 2: Create the compose.yaml file
Create a file named `compose.yaml` with the following contents:
@@ -202,15 +249,16 @@ services:
- 8080:8080
```
### Step 3: Create the .dockerignore file
#### Step 3: Create the .dockerignore file
The `.dockerignore` file tells Docker which files and folders to exclude when building the image.
> [!NOTE]
>This helps:
>- Reduce image size
>- Speed up the build process
>- Prevent sensitive or unnecessary files (like `.env`, `.git`, or `node_modules`) from being added to the final image.
> This helps:
>
> - Reduce image size
> - Speed up the build process
> - Prevent sensitive or unnecessary files (like `.env`, `.git`, or `node_modules`) from being added to the final image.
>
> To learn more, visit the [.dockerignore reference](/reference/dockerfile.md#dockerignore-file).
@@ -280,7 +328,7 @@ docker-compose*.yml
*.tmp
```
### Step 4: Create the `nginx.conf` file
#### Step 4: Create the `nginx.conf` file
To serve your Angular application efficiently inside the container, you’ll configure Nginx with a custom setup. This configuration is optimized for performance, browser caching, gzip compression, and support for client-side routing.
@@ -289,7 +337,6 @@ Create a file named `nginx.conf` in the root of your project directory, and add
> [!NOTE]
> To learn more about configuring Nginx, see the [official Nginx documentation](https://nginx.org/en/docs/).
```nginx
worker_processes auto;
@@ -368,7 +415,7 @@ http {
}
```
### Step 5: Build the Angular application image
#### Step 5: Build the Angular application image
With your custom configuration in place, you're now ready to build the Docker image for your Angular application.
@@ -399,12 +446,12 @@ $ docker build --tag docker-angular-sample .
```
What this command does:
- Uses the Dockerfile in the current directory (.)
- Packages the application and its dependencies into a Docker image
- Tags the image as docker-angular-sample so you can reference it later
### Step 6: View local images
#### Step 6: View local images
After building your Docker image, you can check which images are available on your local machine using either the Docker CLI or [Docker Desktop](/manuals/desktop/use-desktop/images.md). Since you're already working in the terminal, let's use the Docker CLI.
@@ -429,15 +476,14 @@ This output provides key details about your images:
- **Created** – The timestamp indicating when the image was built.
- **Size** – The total disk space used by the image.
If the build was successful, you should see `docker-angular-sample` image listed.
If the build was successful, you should see `docker-angular-sample` image listed.
---
## Run the containerized application
### Run the containerized application
In the previous step, you created a Dockerfile for your Angular application and built a Docker image using the docker build command. Now it’s time to run that image in a container and verify that your application works as expected.
Inside the `docker-angular-sample` directory, run the following command in a
terminal.
@@ -449,7 +495,7 @@ Open a browser and view the application at [http://localhost:8080](http://localh
Press `ctrl+c` in the terminal to stop your application.
### Run the application in the background
#### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `docker-angular-sample` directory, run the following command
@@ -461,7 +507,6 @@ $ docker compose up --build -d
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see your Angular application running in the browser.
To confirm that the container is running, use `docker ps` command:
```console
@@ -477,53 +522,284 @@ CONTAINER ID IMAGE COMMAND CREATED
eb13026806d1 docker-angular-sample-server "nginx -c /etc/nginx…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp docker-angular-sample-server-1
```
To stop the application, run:
```console
$ docker compose down
```
> [!NOTE]
> For more information about Compose commands, see the [Compose CLI
> reference](/reference/cli/docker/compose/).
---
## Summary
## Use containers for Angular development
In this guide, you learned how to containerize, build, and run an Angular application using Docker. By following best practices, you created a secure, optimized, and production-ready setup.
### Prerequisites
Complete [Containerize Angular application](./).
---
### Overview
In this section, you'll learn how to set up both production and development environments for your containerized Angular application using Docker Compose. This setup allows you to serve a static production build via Nginx and to develop efficiently inside containers using a live-reloading dev server with Compose Watch.
You’ll learn how to:
- Configure separate containers for production and development
- Enable automatic file syncing using Compose Watch in development
- Debug and live-preview your changes in real-time without manual rebuilds
---
### Automatically update services (development mode)
Use Compose Watch to automatically sync source file changes into your containerized development environment. This provides a seamless, efficient development experience without restarting or rebuilding containers manually.
### Step 1: Create a development Dockerfile
Create a file named `Dockerfile.dev` in your project root with the following content:
```dockerfile
# =========================================
# Stage 1: Development - Angular Application
# =========================================
# Define the Node.js version to use (Alpine for a small footprint)
ARG NODE_VERSION=24.12.0-alpine
# Set the base image for development
FROM node:${NODE_VERSION} AS dev
# Set environment variable to indicate development mode
ENV NODE_ENV=development
# Set the working directory inside the container
WORKDIR /app
# Copy only the dependency files first to optimize Docker caching
COPY package.json package-lock.json* ./
# Install dependencies using npm with caching to speed up subsequent builds
RUN --mount=type=cache,target=/root/.npm npm install
# Copy all application source files into the container
COPY . .
# Expose the port Angular uses for the dev server (default is 4200)
EXPOSE 4200
# Start the Angular dev server and bind it to all network interfaces
CMD ["npm", "start", "--", "--host=0.0.0.0"]
```
This file sets up a lightweight development environment for your Angular application using the dev server.
#### Step 2: Update your `compose.yaml` file
Open your `compose.yaml` file and define two services: one for production (`angular-prod`) and one for development (`angular-dev`).
Here’s an example configuration for an Angular application:
```yaml
services:
angular-prod:
build:
context: .
dockerfile: Dockerfile
image: docker-angular-sample
ports:
- "8080:8080"
angular-dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "4200:4200"
develop:
watch:
- action: sync
path: .
target: /app
```
- The `angular-prod` service builds and serves your static production app using Nginx.
- The `angular-dev` service runs your Angular development server with live reload and hot module replacement.
- `watch` triggers file sync with Compose Watch.
> [!NOTE]
> For more details, see the official guide: [Use Compose Watch](/manuals/compose/how-tos/file-watch.md).
After completing the previous steps, your project directory should now contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ ├── .dockerignore
│ ├── compose.yaml
│ └── nginx.conf
```
#### Step 4: Start Compose Watch
Run the following command from the project root to start the container in watch mode
```console
$ docker compose watch angular-dev
```
#### Step 5: Test Compose Watch with Angular
To verify that Compose Watch is working correctly:
1. Open the `src/app/app.component.html` file in your text editor.
2. Locate the following line:
```html
<h1>Docker Angular Sample Application</h1>
```
3. Change it to:
```html
<h1>Hello from Docker Compose Watch</h1>
```
4. Save the file.
5. Open your browser at [http://localhost:4200](http://localhost:4200).
You should see the updated text appear instantly, without needing to rebuild the container manually. This confirms that file watching and automatic synchronization are working as expected.
---
## Run Angular tests in a container
### Prerequisites
Complete all the previous sections of this guide, starting with [Containerize Angular application](./).
### Overview
Testing is a critical part of the development process. In this section, you'll learn how to:
- Run Jasmine unit tests using the Angular CLI inside a Docker container.
- Use Docker Compose to isolate your test environment.
- Ensure consistency between local and container-based testing.
The `docker-angular-sample` project comes pre-configured with Jasmine, so you can get started quickly without extra setup.
---
### Run tests during development
The `docker-angular-sample` application includes a sample test file at the following location:
```console
$ src/app/app.component.spec.ts
```
This test uses Jasmine to validate the AppComponent logic.
#### Step 1: Update compose.yaml
Add a new service named `angular-test` to your `compose.yaml` file. This service allows you to run your test suite in an isolated, containerized environment.
```yaml {hl_lines="22-26",linenos=true}
services:
angular-dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "5173:5173"
develop:
watch:
- action: sync
path: .
target: /app
angular-prod:
build:
context: .
dockerfile: Dockerfile
image: docker-angular-sample
ports:
- "8080:8080"
angular-test:
build:
context: .
dockerfile: Dockerfile.dev
command: ["npm", "run", "test"]
```
The angular-test service reuses the same `Dockerfile.dev` used for [development](#use-containers-for-angular-development) and overrides the default command to run tests with `npm run test`. This setup ensures a consistent test environment that matches your local development configuration.
After completing the previous steps, your project directory should contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ ├── .dockerignore
│ ├── compose.yaml
│ └── nginx.conf
```
#### Step 2: Run the tests
To execute your test suite inside the container, run the following command from your project root:
```console
$ docker compose run --rm angular-test
```
This command will:
- Start the `angular-test` service defined in your `compose.yaml` file.
- Execute the `npm run test` script using the same environment as development.
- Automatically removes the container after tests complete, using the [`docker compose run --rm`](/reference/cli/docker/compose/run/) command.
You should see output similar to the following:
```shell
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.529 s
```
> [!NOTE]
> For more information about Compose commands, see the [Compose CLI
> reference](/reference/cli/docker/compose/).
---
### Summary
In this section, you learned how to run unit tests for your Angular application inside a Docker container using Jasmine and Docker Compose.
What you accomplished:
- Created a multi-stage `Dockerfile` that compiles the Angular application and serves the static files using Nginx.
- Created a `.dockerignore` file to exclude unnecessary files and keep the image clean and efficient.
- Built your Docker image using `docker build`.
- Ran the container using `docker compose up`, both in the foreground and in detached mode.
- Verified that the app was running by visiting [http://localhost:8080](http://localhost:8080).
- Learned how to stop the containerized application using `docker compose down`.
You now have a fully containerized Angular application, running in a Docker container, and ready for deployment across any environment with confidence and consistency.
- Created a `angular-test` service in `compose.yaml` to isolate test execution.
- Reused the development `Dockerfile.dev` to ensure consistency between dev and test environments.
- Ran tests inside the container using `docker compose run --rm angular-test`.
- Ensured reliable, repeatable testing across environments without depending on your local machine setup.
---
## Related resources
### Related resources
Explore official references and best practices to sharpen your Docker workflow:
- [Multi-stage builds](/build/building/multi-stage/) – Learn how to separate build and runtime stages.
- [Best practices for writing Dockerfiles](/develop/develop-images/dockerfile_best-practices/) – Write efficient, maintainable, and secure Dockerfiles.
- [Build context in Docker](/build/concepts/context/) – Learn how context affects image builds.
- [`docker build` CLI reference](/reference/cli/docker/image/build/) – Build Docker images from a Dockerfile.
- [`docker images` CLI reference](/reference/cli/docker/image/ls/) – Manage and inspect local Docker images.
- [`docker compose up` CLI reference](/reference/cli/docker/compose/up/) – Start and run multi-container applications.
- [`docker compose down` CLI reference](/reference/cli/docker/compose/down/) – Stop and remove containers, networks, and volumes.
---
## Next steps
With your Angular application now containerized, you're ready to move on to the next step.
In the next section, you'll learn how to develop your application using Docker containers, enabling a consistent, isolated, and reproducible development environment across any machine.
Explore official references and best practices to sharpen your Docker testing workflow:
- [Dockerfile reference](/reference/dockerfile/) – Understand all Dockerfile instructions and syntax.
- [Best practices for writing Dockerfiles](/develop/develop-images/dockerfile_best-practices/) – Write efficient, maintainable, and secure Dockerfiles.
- [Compose file reference](/compose/compose-file/) – Learn the full syntax and options available for configuring services in `compose.yaml`.
- [`docker compose run` CLI reference](/reference/cli/docker/compose/run/) – Run one-off commands in a service container.

View File

@@ -1,134 +0,0 @@
---
title: Run Angular tests in a container
linkTitle: Run your tests
weight: 40
keywords: angular, test, jasmine
description: Learn how to run your Angular tests in a container.
---
## Prerequisites
Complete all the previous sections of this guide, starting with [Containerize Angular application](containerize.md).
## Overview
Testing is a critical part of the development process. In this section, you'll learn how to:
- Run Jasmine unit tests using the Angular CLI inside a Docker container.
- Use Docker Compose to isolate your test environment.
- Ensure consistency between local and container-based testing.
The `docker-angular-sample` project comes pre-configured with Jasmine, so you can get started quickly without extra setup.
---
## Run tests during development
The `docker-angular-sample` application includes a sample test file at the following location:
```console
$ src/app/app.component.spec.ts
```
This test uses Jasmine to validate the AppComponent logic.
### Step 1: Update compose.yaml
Add a new service named `angular-test` to your `compose.yaml` file. This service allows you to run your test suite in an isolated, containerized environment.
```yaml {hl_lines="22-26",linenos=true}
services:
angular-dev:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "5173:5173"
develop:
watch:
- action: sync
path: .
target: /app
angular-prod:
build:
context: .
dockerfile: Dockerfile
image: docker-angular-sample
ports:
- "8080:8080"
angular-test:
build:
context: .
dockerfile: Dockerfile.dev
command: ["npm", "run", "test"]
```
The angular-test service reuses the same `Dockerfile.dev` used for [development](develop.md) and overrides the default command to run tests with `npm run test`. This setup ensures a consistent test environment that matches your local development configuration.
After completing the previous steps, your project directory should contain the following files:
```text
├── docker-angular-sample/
│ ├── Dockerfile
│ ├── Dockerfile.dev
│ ├── .dockerignore
│ ├── compose.yaml
│ └── nginx.conf
```
### Step 2: Run the tests
To execute your test suite inside the container, run the following command from your project root:
```console
$ docker compose run --rm angular-test
```
This command will:
- Start the `angular-test` service defined in your `compose.yaml` file.
- Execute the `npm run test` script using the same environment as development.
- Automatically removes the container after tests complete, using the [`docker compose run --rm`](/reference/cli/docker/compose/run/) command.
You should see output similar to the following:
```shell
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.529 s
```
> [!NOTE]
> For more information about Compose commands, see the [Compose CLI
> reference](/reference/cli/docker/compose/).
---
## Summary
In this section, you learned how to run unit tests for your Angular application inside a Docker container using Jasmine and Docker Compose.
What you accomplished:
- Created a `angular-test` service in `compose.yaml` to isolate test execution.
- Reused the development `Dockerfile.dev` to ensure consistency between dev and test environments.
- Ran tests inside the container using `docker compose run --rm angular-test`.
- Ensured reliable, repeatable testing across environments without depending on your local machine setup.
---
## Related resources
Explore official references and best practices to sharpen your Docker testing workflow:
- [Dockerfile reference](/reference/dockerfile/) – Understand all Dockerfile instructions and syntax.
- [Best practices for writing Dockerfiles](/develop/develop-images/dockerfile_best-practices/) – Write efficient, maintainable, and secure Dockerfiles.
- [Compose file reference](/compose/compose-file/) – Learn the full syntax and options available for configuring services in `compose.yaml`.
- [`docker compose run` CLI reference](/reference/cli/docker/compose/run/) – Run one-off commands in a service container.
---

View File

@@ -5,7 +5,7 @@ summary: |
Learn how to automate Docker image build and push using Azure Pipelines.
keywords: azure pipelines, azure devops, ci/cd, docker hub, build and push, automation
params:
tags: [devops]
tags: [cicd]
time: 10 minutes
---
@@ -308,5 +308,5 @@ With this Azure Pipelines CI setup, you get:
- [Azure Pipelines Documentation](https://learn.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops): Comprehensive guide to configuring and managing CI/CD pipelines in Azure DevOps.
- [Docker Task for Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/build/docker): Detailed reference for using the Docker task in Azure Pipelines to build and push images.
- [Docker Buildx Bake](/manuals/build/bake/_index.md): Explore Docker's advanced build tool for complex, multi-stage, and multi-platform build setups. See also the [Mastering Buildx Bake Guide](/guides/bake/index.md) for practical examples and best practices.
- [Docker Buildx Bake](/manuals/build/bake/_index.md): Explore Docker's advanced build tool for complex, multi-stage, and multi-platform build setups. See also the [Mastering Buildx Bake Guide](/guides/bake/) for practical examples and best practices.
- [Docker Build Cloud](/guides/docker-build-cloud/_index.md): Learn about Docker's managed build service for faster, scalable, and multi-platform image builds in the cloud.

View File

@@ -6,9 +6,8 @@ description: >
summary: >
Learn to automate Docker builds and testing with declarative configurations using Buildx Bake.
keywords: bake, buildx, multi-platform, build configuration, hcl, automation
tags: [devops]
languages: [go]
params:
tags: [cicd]
time: 30 minutes
image: /images/guides/bake.webp
---
@@ -441,9 +440,9 @@ build/
└── bin
├── bakeme
├── linux_amd64
│   └── bakeme
│ └── bakeme
├── linux_arm64
│   └── bakeme
│ └── bakeme
└── linux_riscv64
└── bakeme
@@ -476,17 +475,17 @@ $ tree build/
build/
└── bin
├── debug
│   ├── linux_amd64
│   │   └── bakeme
│   ├── linux_arm64
│   │   └── bakeme
│   └── linux_riscv64
│   └── bakeme
│ ├── linux_amd64
│ │ └── bakeme
│ ├── linux_arm64
│ │ └── bakeme
│ └── linux_riscv64
│ └── bakeme
└── release
├── linux_amd64
│   └── bakeme
│ └── bakeme
├── linux_arm64
│   └── bakeme
│ └── bakeme
└── linux_riscv64
└── bakeme

View File

@@ -1,35 +0,0 @@
---
description: Containerize and develop Bun applications using Docker.
keywords: getting started, bun
title: Bun language-specific guide
summary: |
Learn how to containerize JavaScript applications with the Bun runtime.
linkTitle: Bun
aliases:
- /guides/bun/configure-ci-cd/
- /guides/bun/deploy/
languages: [js]
tags: [dhi]
params:
time: 10 minutes
---
The Bun getting started guide teaches you how to create a containerized Bun application using Docker.
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
## What will you learn?
* Containerize and run a Bun application using Docker
* Set up a local environment to develop a Bun application using containers
## Prerequisites
- Basic understanding of JavaScript is assumed.
- You must have familiarity with Docker concepts like containers, images, and Dockerfiles. If you are new to Docker, you can start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
After completing the Bun getting started modules, you should be able to containerize your own Bun application based on the examples and instructions provided in this guide.
Start by containerizing an existing Bun application.

View File

@@ -1,72 +0,0 @@
---
title: Use containers for Bun development
linkTitle: Develop your app
weight: 20
keywords: bun, local, development
description: Learn how to develop your Bun application locally.
aliases:
- /language/bun/develop/
---
## Prerequisites
Complete [Containerize a Bun application](containerize.md).
## Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Configuring Compose to automatically update your running Compose services as you edit and save your code
## Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/dockersamples/bun-docker.git && cd bun-docker
```
## Automatically update services
Use Compose Watch to automatically update your running Compose services as you
edit and save your code. For more details about Compose Watch, see [Use Compose
Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yml` file in an IDE or text editor and then add the Compose Watch instructions. The following example shows how to add Compose Watch to your `compose.yml` file.
```yaml {hl_lines="9-12",linenos=true}
services:
server:
image: bun-server
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
develop:
watch:
- action: rebuild
path: .
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Now, if you modify your `server.js` you will see the changes in real time without re-building the image.
To test it out, open the `server.js` file in your favorite text editor and change the message from `{"Status" : "OK"}` to `{"Status" : "Updated"}`. Save the file and refresh your browser at `http://localhost:3000`. You should see the updated message.
Press `ctrl+c` in the terminal to stop your application.
## Summary
In this section, you also learned how to use Compose Watch to automatically rebuild and run your container when you update your code.
Related information:
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)

View File

@@ -1,18 +1,47 @@
---
title: Containerize a Bun application
linkTitle: Containerize your app
weight: 10
keywords: bun, containerize, initialize
description: Learn how to containerize a Bun application.
description: Containerize and develop Bun applications using Docker.
keywords: getting started, bun
title: Bun language-specific guide
summary: |
Learn how to containerize JavaScript applications with the Bun runtime.
linkTitle: Bun
aliases:
- /language/bun/containerize/
- /guides/bun/configure-ci-cd/
- /guides/bun/containerize/
- /guides/bun/deploy/
- /guides/bun/develop/
params:
tags: [languages]
time: 10 minutes
---
The Bun getting started guide teaches you how to create a containerized Bun application using Docker.
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
## What will you learn?
- Containerize and run a Bun application using Docker
- Set up a local environment to develop a Bun application using containers
## Prerequisites
* You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
- Basic understanding of JavaScript is assumed.
- You must have familiarity with Docker concepts like containers, images, and Dockerfiles. If you are new to Docker, you can start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
## Overview
After completing the Bun getting started modules, you should be able to containerize your own Bun application based on the examples and instructions provided in this guide.
Start by containerizing an existing Bun application.
## Containerize a Bun application
### Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
### Overview
For a long time, Node.js has been the de-facto runtime for server-side
JavaScript applications. Recent years have seen a rise in new alternative
@@ -29,7 +58,7 @@ dependencies. Also, as it's fairly a new runtime, getting a consistent
development environment for Bun can be challenging. Docker can help you set up
a consistent development environment for Bun.
## Get the sample application
### Get the sample application
Clone the sample application to use with this guide. Open a terminal, change
directory to a directory that you want to work in, and run the following
@@ -50,7 +79,7 @@ You should now have the following contents in your `bun-docker` directory.
│ └── README.md
```
## Create a Dockerfile
### Create a Dockerfile
Before creating a Dockerfile, you need to choose a base image. You can either use the [Bun Docker Official Image](https://hub.docker.com/r/oven/bun) or a Docker Hardened Image (DHI) from the [Hardened Image catalog](https://hub.docker.com/hardened-images/catalog).
@@ -62,6 +91,7 @@ Choosing DHI offers the advantage of a production-ready image that is lightweigh
Docker Hardened Images (DHIs) are available for Bun in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/bun). You can pull DHIs directly from the `dhi.io` registry.
1. Sign in to the DHI registry:
```console
$ docker login dhi.io
```
@@ -125,7 +155,7 @@ In addition to specifying the base image, the Dockerfile also:
- Exposes port 3000, where the API is listening for requests.
- And finally, starts the server when the container launches with the command `bun server.js`.
## Run the application
### Run the application
Inside the `bun-docker` directory, run the following command in a terminal.
@@ -137,7 +167,7 @@ Open a browser and view the application at [http://localhost:3000](http://localh
In the terminal, press `ctrl`+`c` to stop the application.
### Run the application in the background
#### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `bun-docker` directory, run the following command
@@ -149,27 +179,73 @@ $ docker compose up --build -d
Open a browser and view the application at [http://localhost:3000](http://localhost:3000).
In the terminal, run the following command to stop the application.
```console
$ docker compose down
```
## Summary
## Use containers for Bun development
In this section, you learned how you can containerize and run your Bun
application using Docker.
### Prerequisites
Complete [Containerize a Bun application](./).
### Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Configuring Compose to automatically update your running Compose services as you edit and save your code
### Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/dockersamples/bun-docker.git && cd bun-docker
```
### Automatically update services
Use Compose Watch to automatically update your running Compose services as you
edit and save your code. For more details about Compose Watch, see [Use Compose
Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yml` file in an IDE or text editor and then add the Compose Watch instructions. The following example shows how to add Compose Watch to your `compose.yml` file.
```yaml {hl_lines="9-12",linenos=true}
services:
server:
image: bun-server
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
develop:
watch:
- action: rebuild
path: .
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Now, if you modify your `server.js` you will see the changes in real time without re-building the image.
To test it out, open the `server.js` file in your favorite text editor and change the message from `{"Status" : "OK"}` to `{"Status" : "Updated"}`. Save the file and refresh your browser at `http://localhost:3000`. You should see the updated message.
Press `ctrl+c` in the terminal to stop your application.
### Summary
In this section, you also learned how to use Compose Watch to automatically rebuild and run your container when you update your code.
Related information:
- [Dockerfile reference](/reference/dockerfile.md)
- [.dockerignore file](/reference/dockerfile.md#dockerignore-file)
- [Docker Compose overview](/manuals/compose/_index.md)
- [Compose file reference](/reference/compose-file/_index.md)
- [Docker Hardened Images](/dhi/)
## Next steps
In the next section, you'll learn how you can develop your application using
containers.
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)

View File

@@ -5,8 +5,8 @@ summary: |
Connect Claude Code to Docker Model Runner with the Anthropic-compatible API,
package `gpt-oss` with a larger context window, and inspect requests.
keywords: ai, claude code, docker model runner, anthropic, local models, coding assistant
tags: [ai]
params:
tags: [ai]
time: 10 minutes
---

View File

@@ -6,8 +6,8 @@ summary: |
isolated microVM that talks to a local model on your host through the
Anthropic-compatible API.
keywords: ai, claude code, docker model runner, docker sandboxes, sbx, anthropic, local models, coding assistant
tags: [ai]
params:
tags: [ai]
time: 15 minutes
---

View File

@@ -4,9 +4,8 @@ description: Learn how to build Docker Compose projects with Docker Buildx Bake
summary: |
This guide demonstrates how you can use Bake to build production-grade images for Docker Compose projects.
keywords: docker compose, bake, buildx, multi-service, production builds, build configuration
languages: []
tags: [devops]
params:
tags: [cicd]
time: 20 minutes
---
@@ -211,7 +210,7 @@ $ docker buildx bake
Start by redefining the default build group that Bake executes. The current
default group includes a `seed` target — a Compose service used solely to
populate the database with mock data. Since this target doesn't produce a
production image, it doesn’t need to be included in the build group.
production image, it doesn't need to be included in the build group.
To customize the build configuration that Bake uses, create a new file at the
root of the repository, alongside your `compose.yaml` file, named
@@ -399,5 +398,5 @@ For more information about how to use Bake, check out these resources:
- [Bake documentation](/manuals/build/bake/_index.md)
- [Building with Bake from a Compose file](/manuals/build/bake/compose-file.md)
- [Bake file reference](/manuals/build/bake/reference.md)
- [Mastering multi-platform builds, testing, and more with Docker Buildx Bake](/guides/bake/index.md)
- [Mastering multi-platform builds, testing, and more with Docker Buildx Bake](/guides/bake/)
- [Bake GitHub Action](https://github.com/docker/bake-action)

View File

@@ -6,8 +6,8 @@ summary: |
description: |
Use containers in your local development loop to develop and test faster… even if your main app isn't running in containers.
keywords: containers, local development, dependent services, testing, debugging, development environment
tags: [app-dev]
params:
tags: [cicd]
image: images/learning-paths/container-supported-development.png
time: 20 minutes
resource_links: []

View File

@@ -1,37 +0,0 @@
---
title: C++ language-specific guide
linkTitle: C++
description: Containerize and develop C++ applications using Docker.
keywords: getting started, c++
summary: |
This guide explains how to containerize C++ applications using Docker.
toc_min: 1
toc_max: 2
aliases:
- /language/cpp/
- /guides/language/cpp/
- /guides/cpp/configure-ci-cd/
- /language/cpp/configure-ci-cd/
- /guides/language/cpp/configure-ci-cd/
- /guides/cpp/deploy/
- /language/cpp/deploy/
- /guides/language/cpp/deploy/
- /guides/cpp/security/
languages: [cpp]
params:
time: 20 minutes
---
The C++ getting started guide teaches you how to create a containerized C++ application using Docker. In this guide, you'll learn how to:
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) and [Mohammad-Ali A'râbi](https://twitter.com/MohammadAliEN) for their contribution to this guide.
- Containerize and run a C++ application using a multi-stage Docker build
- Build and run a C++ application using Docker Compose
- Set up a local environment to develop a C++ application using containers
After completing the C++ getting started modules, you should be able to containerize your own C++ application based on the examples and instructions provided in this guide.
Start by containerizing an existing C++ application.

View File

@@ -1,93 +0,0 @@
---
title: Containerize a C++ application
linkTitle: Containerize
weight: 10
keywords: C++, containerize, initialize
description: Learn how to use Docker Compose to build and run a C++ application.
aliases:
- /language/cpp/containerize/
- /guides/language/cpp/containerize/
---
## Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
## Overview
This section walks you through containerizing and running a C++ application, using Docker Compose.
## Get the sample application
We're using the same sample repository that you used in the previous sections of this guide. If you haven't already cloned the repository, clone it now:
```console
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
```
You should now have the following contents in your `c-plus-plus-docker` (root)
directory.
```text
├── c-plus-plus-docker/
│ ├── compose.yml
│ ├── Dockerfile
│ ├── LICENSE
│ ├── ok_api.cpp
│ └── README.md
```
To learn more about the files in the repository, see the following:
- [Dockerfile](/reference/dockerfile.md)
- [.dockerignore](/reference/dockerfile.md#dockerignore-file)
- [compose.yml](/reference/compose-file/_index.md)
## Run the application
Inside the `c-plus-plus-docker` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You will see a message `{"Status" : "OK"}` in the browser.
In the terminal, press `ctrl`+`c` to stop the application.
### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `c-plus-plus-docker` directory, run the following command
in a terminal.
```console
$ docker compose up --build -d
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080).
In the terminal, run the following command to stop the application.
```console
$ docker compose down
```
For more information about Compose commands, see the [Compose CLI
reference](/reference/cli/docker/compose/).
## Summary
In this section, you learned how you can containerize and run your C++
application using Docker.
Related information:
- [Docker Compose overview](/manuals/compose/_index.md)
## Next steps
In the next section, you'll learn how you can develop your application using
containers.

View File

@@ -1,74 +0,0 @@
---
title: Use containers for C++ development
linkTitle: Develop your app
weight: 20
keywords: C++, local, development
description: Learn how to develop your C++ application locally.
aliases:
- /language/cpp/develop/
- /guides/language/cpp/develop/
---
## Prerequisites
Complete [Containerize a C++ application](containerize.md).
## Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Configuring Compose to automatically update your running Compose services as you edit and save your code
## Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git && cd c-plus-plus-docker
```
## Automatically update services
Use Compose Watch to automatically update your running Compose services as you
edit and save your code. For more details about Compose Watch, see [Use Compose
Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yml` file in an IDE or text editor and then add the Compose Watch instructions. The following example shows how to add Compose Watch to your `compose.yml` file.
```yaml {hl_lines="11-14",linenos=true}
services:
ok-api:
image: ok-api
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
develop:
watch:
- action: rebuild
path: .
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Now, if you modify your `ok_api.cpp` you will see the changes in real time without re-building the image.
To test it out, open the `ok_api.cpp` file in your favorite text editor and change the message from `{"Status" : "OK"}` to `{"Status" : "Updated"}`. Save the file and refresh your browser at [http://localhost:8080](http://localhost:8080). You should see the updated message.
Press `ctrl+c` in the terminal to stop your application.
## Summary
In this section, you also learned how to use Compose Watch to automatically rebuild and run your container when you update your code.
Related information:
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)

276
content/guides/cpp/index.md Normal file
View File

@@ -0,0 +1,276 @@
---
title: C++ language-specific guide
linkTitle: C++
description: Containerize and develop C++ applications using Docker.
keywords: getting started, c++
summary: |
This guide explains how to containerize C++ applications using Docker.
aliases:
- /language/cpp/
- /guides/language/cpp/
- /language/cpp/containerize/
- /language/cpp/develop/
- /language/cpp/configure-ci-cd/
- /language/cpp/deploy/
- /guides/cpp/configure-ci-cd/
- /guides/cpp/containerize/
- /guides/cpp/deploy/
- /guides/cpp/develop/
- /guides/cpp/multistage/
- /guides/cpp/security/
params:
tags: [languages]
time: 20 minutes
---
The C++ getting started guide teaches you how to create a containerized C++ application using Docker. In this guide, you'll learn how to:
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) and [Mohammad-Ali A'râbi](https://twitter.com/MohammadAliEN) for their contribution to this guide.
- Containerize and run a C++ application using a multi-stage Docker build
- Build and run a C++ application using Docker Compose
- Set up a local environment to develop a C++ application using containers
After completing the C++ getting started modules, you should be able to containerize your own C++ application based on the examples and instructions provided in this guide.
Start by containerizing an existing C++ application.
## Create a multi-stage build for your C++ application
### Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
### Overview
This section walks you through creating a multi-stage Docker build for a C++ application.
A multi-stage build is a Docker feature that allows you to use different base images for different stages of the build process,
so you can optimize the size of your final image and separate build dependencies from runtime dependencies.
The standard practice for compiled languages like C++ is to have a build stage that compiles the code and a runtime stage that runs the compiled binary,
because the build dependencies are not needed at runtime.
### Get the sample application
Let's use a simple C++ application that prints `Hello, World!` to the terminal. To do so, clone the sample repository to use with this guide:
```bash
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
```
The example for this section is under the `hello` directory in the repository. Get inside it and take a look at the files:
```bash
$ cd c-plus-plus-docker/hello
$ ls
```
You should see the following files:
```text
Dockerfile hello.cpp
```
### Check the Dockerfile
Open the `Dockerfile` in an IDE or text editor. The `Dockerfile` contains the instructions for building the Docker image.
```Dockerfile
# Stage 1: Build stage
FROM ubuntu:latest AS build
# Install build-essential for compiling C++ code
RUN apt-get update && apt-get install -y build-essential
# Set the working directory
WORKDIR /app
# Copy the source code into the container
COPY hello.cpp .
# Compile the C++ code statically to ensure it doesn't depend on runtime libraries
RUN g++ -o hello hello.cpp -static
# Stage 2: Runtime stage
FROM scratch
# Copy the static binary from the build stage
COPY --from=build /app/hello /hello
# Command to run the binary
CMD ["/hello"]
```
The `Dockerfile` has two stages:
1. **Build stage**: This stage uses the `ubuntu:latest` image to compile the C++ code and create a static binary.
2. **Runtime stage**: This stage uses the `scratch` image, which is an empty image, to copy the static binary from the build stage and run it.
### Build the Docker image
To build the Docker image, run the following command in the `hello` directory:
```bash
$ docker build -t hello .
```
The `-t` flag tags the image with the name `hello`.
### Run the Docker container
To run the Docker container, use the following command:
```bash
$ docker run hello
```
You should see the output `Hello, World!` in the terminal.
Because the final image uses an empty `scratch` base, it contains only the
static binary and none of the build dependencies or usual OS tools. For
example, you can't run a simple `ls` command in the container:
```bash
$ docker run hello ls
```
The absence of a shell and other tools keeps the image small and reduces its
attack surface.
## Containerize a C++ application
### Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
### Overview
This section walks you through containerizing and running a C++ application, using Docker Compose.
### Get the sample application
We're using the same sample repository that you used in the previous sections of this guide. If you haven't already cloned the repository, clone it now:
```console
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
```
You should now have the following contents in your `c-plus-plus-docker` (root)
directory.
```text
├── c-plus-plus-docker/
│ ├── compose.yml
│ ├── Dockerfile
│ ├── LICENSE
│ ├── ok_api.cpp
│ └── README.md
```
To learn more about the files in the repository, see the following:
- [Dockerfile](/reference/dockerfile.md)
- [.dockerignore](/reference/dockerfile.md#dockerignore-file)
- [compose.yml](/reference/compose-file/_index.md)
### Run the application
Inside the `c-plus-plus-docker` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You will see a message `{"Status" : "OK"}` in the browser.
In the terminal, press `ctrl`+`c` to stop the application.
#### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `c-plus-plus-docker` directory, run the following command
in a terminal.
```console
$ docker compose up --build -d
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080).
In the terminal, run the following command to stop the application.
```console
$ docker compose down
```
For more information about Compose commands, see the [Compose CLI
reference](/reference/cli/docker/compose/).
## Use containers for C++ development
### Prerequisites
Complete [Containerize a C++ application](./).
### Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Configuring Compose to automatically update your running Compose services as you edit and save your code
### Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git && cd c-plus-plus-docker
```
### Automatically update services
Use Compose Watch to automatically update your running Compose services as you
edit and save your code. For more details about Compose Watch, see [Use Compose
Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yml` file in an IDE or text editor and then add the Compose Watch instructions. The following example shows how to add Compose Watch to your `compose.yml` file.
```yaml {hl_lines="11-14",linenos=true}
services:
ok-api:
image: ok-api
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
develop:
watch:
- action: rebuild
path: .
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Now, if you modify your `ok_api.cpp` you will see the changes in real time without re-building the image.
To test it out, open the `ok_api.cpp` file in your favorite text editor and change the message from `{"Status" : "OK"}` to `{"Status" : "Updated"}`. Save the file and refresh your browser at [http://localhost:8080](http://localhost:8080). You should see the updated message.
Press `ctrl+c` in the terminal to stop your application.
### Summary
In this section, you also learned how to use Compose Watch to automatically rebuild and run your container when you update your code.
Related information:
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)

View File

@@ -1,112 +0,0 @@
---
title: Create a multi-stage build for your C++ application
linkTitle: Multi-stage build
weight: 5
keywords: C++, containerize, multi-stage
description: Learn how to create a multi-stage build for a C++ application.
aliases:
- /language/cpp/multistage/
- /guides/language/cpp/multistage/
---
## Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
## Overview
This section walks you through creating a multi-stage Docker build for a C++ application.
A multi-stage build is a Docker feature that allows you to use different base images for different stages of the build process,
so you can optimize the size of your final image and separate build dependencies from runtime dependencies.
The standard practice for compiled languages like C++ is to have a build stage that compiles the code and a runtime stage that runs the compiled binary,
because the build dependencies are not needed at runtime.
## Get the sample application
Let's use a simple C++ application that prints `Hello, World!` to the terminal. To do so, clone the sample repository to use with this guide:
```bash
$ git clone https://github.com/dockersamples/c-plus-plus-docker.git
```
The example for this section is under the `hello` directory in the repository. Get inside it and take a look at the files:
```bash
$ cd c-plus-plus-docker/hello
$ ls
```
You should see the following files:
```text
Dockerfile hello.cpp
```
## Check the Dockerfile
Open the `Dockerfile` in an IDE or text editor. The `Dockerfile` contains the instructions for building the Docker image.
```Dockerfile
# Stage 1: Build stage
FROM ubuntu:latest AS build
# Install build-essential for compiling C++ code
RUN apt-get update && apt-get install -y build-essential
# Set the working directory
WORKDIR /app
# Copy the source code into the container
COPY hello.cpp .
# Compile the C++ code statically to ensure it doesn't depend on runtime libraries
RUN g++ -o hello hello.cpp -static
# Stage 2: Runtime stage
FROM scratch
# Copy the static binary from the build stage
COPY --from=build /app/hello /hello
# Command to run the binary
CMD ["/hello"]
```
The `Dockerfile` has two stages:
1. **Build stage**: This stage uses the `ubuntu:latest` image to compile the C++ code and create a static binary.
2. **Runtime stage**: This stage uses the `scratch` image, which is an empty image, to copy the static binary from the build stage and run it.
## Build the Docker image
To build the Docker image, run the following command in the `hello` directory:
```bash
$ docker build -t hello .
```
The `-t` flag tags the image with the name `hello`.
## Run the Docker container
To run the Docker container, use the following command:
```bash
$ docker run hello
```
You should see the output `Hello, World!` in the terminal.
## Summary
In this section, you learned how to create a multi-stage build for a C++ application. Multi-stage builds help you optimize the size of your final image and separate build dependencies from runtime dependencies.
In this example, the final image only contains the static binary and doesn't include any build dependencies.
As the image has an empty base, the usual OS tools are also absent. So, for example, you can't run a simple `ls` command in the container:
```bash
$ docker run hello ls
```
This makes the image very lightweight and secure.

View File

@@ -4,10 +4,10 @@ keywords: database, mysql
title: Use containerized databases
summary: |
Learn how to effectively run and manage databases as containers.
tags: [databases]
aliases:
- /guides/use-case/databases/
params:
tags: [databases]
time: 20 minutes
---

View File

@@ -1,36 +0,0 @@
---
description: Containerize and develop Deno applications using Docker.
keywords: getting started, deno
title: Deno language-specific guide
summary: |
Learn how to containerize JavaScript applications with the Deno runtime using Docker.
linkTitle: Deno
aliases:
- /guides/deno/configure-ci-cd/
- /guides/deno/deploy/
languages: [js]
tags: [dhi]
params:
time: 10 minutes
---
The Deno getting started guide teaches you how to create a containerized Deno application using Docker.
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
## What will you learn?
* Containerize and run a Deno application using Docker
* Set up a local environment to develop a Deno application using containers
* Use Docker Compose to run the application.
## Prerequisites
- Basic understanding of JavaScript is assumed.
- You must have familiarity with Docker concepts like containers, images, and Dockerfiles. If you are new to Docker, you can start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
After completing the Deno getting started modules, you should be able to containerize your own Deno application based on the examples and instructions provided in this guide.
Start by containerizing an existing Deno application.

View File

@@ -1,72 +0,0 @@
---
title: Use containers for Deno development
linkTitle: Develop your app
weight: 20
keywords: deno, local, development
description: Learn how to develop your Deno application locally.
aliases:
- /language/deno/develop/
---
## Prerequisites
Complete [Containerize a Deno application](containerize.md).
## Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Configuring Compose to automatically update your running Compose services as you edit and save your code
## Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/dockersamples/docker-deno.git && cd docker-deno
```
## Automatically update services
Use Compose Watch to automatically update your running Compose services as you
edit and save your code. For more details about Compose Watch, see [Use Compose
Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yml` file in an IDE or text editor and then add the Compose Watch instructions. The following example shows how to add Compose Watch to your `compose.yml` file.
```yaml {hl_lines="9-12",linenos=true}
services:
server:
image: deno-server
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
develop:
watch:
- action: rebuild
path: .
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Now, if you modify your `server.ts` you will see the changes in real time without re-building the image.
To test it out, open the `server.ts` file in your favorite text editor and change the message from `{"Status" : "OK"}` to `{"Status" : "Updated"}`. Save the file and refresh your browser at `http://localhost:8000`. You should see the updated message.
Press `ctrl+c` in the terminal to stop your application.
## Summary
In this section, you also learned how to use Compose Watch to automatically rebuild and run your container when you update your code.
Related information:
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)

View File

@@ -1,24 +1,54 @@
---
title: Containerize a Deno application
linkTitle: Containerize your app
weight: 10
keywords: deno, containerize, initialize
description: Learn how to containerize a Deno application.
description: Containerize and develop Deno applications using Docker.
keywords: getting started, deno
title: Deno language-specific guide
summary: |
Learn how to containerize JavaScript applications with the Deno runtime using Docker.
linkTitle: Deno
aliases:
- /language/deno/containerize/
- /guides/deno/configure-ci-cd/
- /guides/deno/containerize/
- /guides/deno/deploy/
- /guides/deno/develop/
params:
tags: [languages]
time: 10 minutes
---
The Deno getting started guide teaches you how to create a containerized Deno application using Docker.
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
## What will you learn?
- Containerize and run a Deno application using Docker
- Set up a local environment to develop a Deno application using containers
- Use Docker Compose to run the application.
## Prerequisites
* You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
- Basic understanding of JavaScript is assumed.
- You must have familiarity with Docker concepts like containers, images, and Dockerfiles. If you are new to Docker, you can start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
## Overview
After completing the Deno getting started modules, you should be able to containerize your own Deno application based on the examples and instructions provided in this guide.
Start by containerizing an existing Deno application.
## Containerize a Deno application
### Prerequisites
- You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
### Overview
For a long time, Node.js has been the go-to runtime for server-side JavaScript applications. However, recent years have introduced new alternative runtimes, including [Deno](https://deno.land/). Like Node.js, Deno is a JavaScript and TypeScript runtime, but it takes a fresh approach with modern security features, a built-in standard library, and native support for TypeScript.
Why develop Deno applications with Docker? Having a choice of runtimes is exciting, but managing multiple runtimes and their dependencies consistently across environments can be tricky. This is where Docker proves invaluable. Using containers to create and destroy environments on demand simplifies runtime management and ensures consistency. Additionally, as Deno continues to grow and evolve, Docker helps establish a reliable and reproducible development environment, minimizing setup challenges and streamlining the workflow.
## Get the sample application
### Get the sample application
Clone the sample application to use with this guide. Open a terminal, change
directory to a directory that you want to work in, and run the following
@@ -39,7 +69,7 @@ You should now have the following contents in your `deno-docker` directory.
│ └── README.md
```
## Understand the sample application
### Understand the sample application
The sample application is a simple Deno application that uses the Oak framework to create a simple API that returns a JSON response. The application listens on port 8000 and returns a message `{"Status" : "OK"}` when you access the application in a browser.
@@ -63,7 +93,7 @@ console.log("Server running on http://localhost:8000");
await app.listen({ port: 8000 });
```
## Create a Dockerfile
### Create a Dockerfile
Before creating a Dockerfile, you need to choose a base image. You can either use the [Deno Docker Official Image](https://hub.docker.com/r/denoland/deno) or a Docker Hardened Image (DHI) from the [Hardened Image catalog](https://hub.docker.com/hardened-images/catalog).
@@ -147,7 +177,7 @@ In addition to specifying the base image, the Dockerfile also:
- Runs the Deno server using the `CMD` instruction.
- Uses the `--allow-net` flag to allow network access to the application. The `server.ts` file uses the Oak framework to create a simple API that listens on port 8000.
## Run the application
### Run the application
Make sure you are in the `deno-docker` directory. Run the following command in a terminal to build and run the application.
@@ -159,7 +189,7 @@ Open a browser and view the application at [http://localhost:8000](http://localh
In the terminal, press `ctrl`+`c` to stop the application.
### Run the application in the background
#### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `deno-docker` directory, run the following command
@@ -171,27 +201,73 @@ $ docker compose up --build -d
Open a browser and view the application at [http://localhost:8000](http://localhost:8000).
In the terminal, run the following command to stop the application.
```console
$ docker compose down
```
## Summary
## Use containers for Deno development
In this section, you learned how you can containerize and run your Deno
application using Docker.
### Prerequisites
Complete [Containerize a Deno application](./).
### Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Configuring Compose to automatically update your running Compose services as you edit and save your code
### Get the sample application
Clone the sample application to use with this guide. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/dockersamples/docker-deno.git && cd docker-deno
```
### Automatically update services
Use Compose Watch to automatically update your running Compose services as you
edit and save your code. For more details about Compose Watch, see [Use Compose
Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yml` file in an IDE or text editor and then add the Compose Watch instructions. The following example shows how to add Compose Watch to your `compose.yml` file.
```yaml {hl_lines="9-12",linenos=true}
services:
server:
image: deno-server
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
develop:
watch:
- action: rebuild
path: .
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Now, if you modify your `server.ts` you will see the changes in real time without re-building the image.
To test it out, open the `server.ts` file in your favorite text editor and change the message from `{"Status" : "OK"}` to `{"Status" : "Updated"}`. Save the file and refresh your browser at `http://localhost:8000`. You should see the updated message.
Press `ctrl+c` in the terminal to stop your application.
### Summary
In this section, you also learned how to use Compose Watch to automatically rebuild and run your container when you update your code.
Related information:
- [Dockerfile reference](/reference/dockerfile.md)
- [.dockerignore file](/reference/dockerfile.md#dockerignore-file)
- [Docker Compose overview](/manuals/compose/_index.md)
- [Compose file reference](/reference/compose-file/_index.md)
- [Docker Hardened Images](/dhi/)
## Next steps
In the next section, you'll learn how you can develop your application using
containers.
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)

View File

@@ -4,9 +4,8 @@ description: &desc Mocking OAuth services in testing with Dex
keywords: Dex, container-supported development
linktitle: Mocking OAuth services with Dex
summary: *desc
tags: [app-dev, distributed-systems]
languages: []
params:
tags: [testing]
time: 10 minutes
---

View File

@@ -3,8 +3,8 @@ title: Secure a Backstage application with Docker Hardened Images
description: Secure a Backstage developer portal using Docker Hardened Images, covering native module compilation, Socket Firewall protection, and distroless runtime images.
summary: Learn how to secure a Backstage developer portal using Docker Hardened Images (DHI), handle native module compilation with better-sqlite3, add Socket Firewall protection during dependency installation, and produce a distroless runtime image using DHI customizations.
keywords: docker hardened images, dhi, backstage, CNCF, developer portal, node.js, native modules, sqlite, better-sqlite3, distroless, socket firewall, dhictl, multi-stage build
tags: ["Docker Hardened Images", "dhi"]
params:
tags: [security]
proficiencyLevel: Intermediate
time: 45 minutes
prerequisites:

View File

@@ -1,13 +0,0 @@
---
title: Migrate to DHI from Docker Official Images
summary: Step-by-step guide to migrate from Docker Official Images to Docker Hardened Images
keywords: docker hardened images, dhi, docker official images, migration, secure images
type: redirect
target: /dhi/migration/migrate-from-doi/
tags: [dhi]
languages: []
params:
time: 10 minutes
featured: true
image: /images/guides/dhi-migrate-doi.webp
---

View File

@@ -1,13 +0,0 @@
---
title: Migrate to DHI from Wolfi
summary: Step-by-step guide to migrate from Wolfi to Docker Hardened Images
keywords: docker hardened images, dhi, wolfi, migration, secure images, distroless
type: redirect
target: /dhi/migration/migrate-from-wolfi/
tags: [dhi]
languages: []
params:
time: 10 minutes
featured: true
image: /images/guides/dhi-migrate-wolfi.webp
---

View File

@@ -1,14 +0,0 @@
---
title: Migrate a Go app to DHI
summary: |
Example showing how to migrate a Go application to Docker Hardened Images
keywords: docker hardened images, dhi, go, golang, migration, secure images
type: redirect
target: /dhi/migration/examples/go/
tags: [dhi]
languages: []
params:
time: 10 minutes
featured: true
image: /images/guides/dhi-examples-go.webp
---

View File

@@ -1,15 +0,0 @@
---
title: Migrate a Node.js app to DHI
summary: |
Example showing how to migrate a Node.js application to Docker Hardened
Images
keywords: docker hardened images, dhi, node.js, nodejs, migration, secure images
type: redirect
target: /dhi/migration/examples/node/
tags: [dhi]
languages: []
params:
time: 10 minutes
featured: true
image: /images/guides/dhi-examples-nodejs.webp
---

View File

@@ -3,8 +3,8 @@ title: Use Docker Hardened Images with Red Hat OpenShift
description: Deploy Docker Hardened Images on Red Hat OpenShift Container Platform, covering Security Context Constraints, arbitrary user ID assignment, file permissions, and best practices.
summary: Learn how to deploy Docker Hardened Images (DHI) on Red Hat OpenShift, configure Security Context Constraints, handle arbitrary user ID assignment, and set file permissions for both runtime and development image variants.
keywords: docker hardened images, dhi, openshift, OCP, SCC, security context constraints, non-root, distroless, containers, red hat
tags: ["Docker Hardened Images", "dhi"]
params:
tags: [security]
proficiencyLevel: Intermediate
time: 30 minutes
prerequisites:

View File

@@ -1,14 +0,0 @@
---
title: Migrate a Python app to DHI
summary: |
Example showing how to migrate a Python application to Docker Hardened Images
keywords: docker hardened images, dhi, python, migration, secure images
type: redirect
target: /dhi/migration/examples/python/
tags: [dhi]
languages: []
params:
time: 10 minutes
featured: true
image: /images/guides/dhi-examples-python.webp
---

View File

@@ -7,8 +7,10 @@ summary: >
Scan a Docker Hardened Image with and without VEX and audit every suppression
and its justification.
keywords: vex, openvex, not_affected, under_investigation, affected, cve, docker scout, dhi, vulnerability
tags: [dhi]
weight: 1
params:
tags: [security]
featured: true
proficiencyLevel: Intermediate
time: 25 minutes
---

View File

@@ -8,9 +8,8 @@ summary: |
You'll scaffold the project with uv, create a production-ready Dockerfile
using a Docker Hardened Image, then add a development stage and Compose Watch
for fast iteration.
languages: [python]
tags: [dhi]
params:
tags: [security]
time: 25 minutes
---

View File

@@ -1,60 +0,0 @@
---
title: "Docker Build Cloud: Reclaim your time with fast, multi-architecture builds"
linkTitle: Docker Build Cloud
description: |
Learn how to build and deploy Docker images to the cloud with Docker Build
Cloud.
summary: |
Build applications up to 39x faster using cloud-based resources, shared team
cache, and native multi-architecture support.
keywords: docker build cloud, cloud builds, multi-architecture, shared cache, ci/cd, build performance
tags: [product-demo]
aliases:
- /learning-paths/docker-build-cloud/
params:
image: images/learning-paths/build-cloud.png
time: 10 minutes
resource_links:
- title: Product page
url: https://www.docker.com/products/build-cloud/
- title: Docker Build Cloud overview
url: /build-cloud/
- title: Subscriptions and features
url: "https://www.docker.com/pricing?ref=Docs&refAction=DocsGuidesBuildCloud"
- title: Using Docker Build Cloud
url: /build-cloud/usage/
---
<!-- vale Vale.Spelling = NO -->
98% of developers spend up to an hour every day waiting for builds to finish
([Incredibuild: 2022 Big Dev Build Times](https://www.incredibuild.com/survey-report-2022)).
Heavy, complex builds can become a major roadblock for development teams,
slowing down both local development and CI/CD pipelines.
<!-- vale Vale.Spelling = YES -->
Docker Build Cloud speeds up image build times to improve developer
productivity, reduce frustrations, and help you shorten the release cycle.
## Who’s this for?
- Anyone who wants to tackle common causes of slow image builds: limited local
resources, slow emulation, and lack of build collaboration across a team.
- Developers working on older machines who want to build faster.
- Development teams working on the same repository who want to cut wait times
with a shared cache.
- Developers performing multi-architecture builds who don’t want to spend hours
configuring and rebuilding for emulators.
## What you’ll learn
- Building container images faster locally and in CI
- Accelerating builds for multi-platform images
- Reusing pre-built images to expedite workflows
## Tools integration
Works well with Docker Compose, GitHub Actions, and other CI solutions
<div id="dbc-lp-survey-anchor"></div>

View File

@@ -1,23 +0,0 @@
---
title: "Demo: Using Docker Build Cloud in CI"
description: Learn how to use Docker Build Cloud to build your app faster in CI.
keywords: docker build cloud, ci/cd, github actions, cloud builds, build performance
weight: 30
---
Docker Build Cloud can significantly decrease the time it takes for your CI builds
take to run, saving you time and money.
Since the builds run remotely, your CI runner can still use the Docker tooling CLI
without needing elevated permissions, making your builds more secure by default.
In this demo, you will see:
- How to integrate Docker Build Cloud into a variety of CI platforms
- How to use Docker Build Cloud in GitHub Actions to build multi-architecture images
- Speed differences between a workflow using Docker Build Cloud and a workflow running natively
- How to use Docker Build Cloud in a GitLab Pipeline
{{< youtube-embed "wvLdInoVBGg" >}}
<div id="dbc-lp-survey-anchor"></div>

View File

@@ -1,63 +0,0 @@
---
title: Common challenges and questions
description: Explore common challenges and questions related to Docker Build Cloud.
keywords: docker build cloud, faq, troubleshooting, cloud builds, pricing
weight: 40
---
### Is Docker Build Cloud a standalone product or a part of Docker Desktop?
Docker Build Cloud is a service that can be used both with Docker Desktop and
standalone. It lets you build your container images faster, both locally and in
CI, with builds running on cloud infrastructure. The service uses a remote
build cache, ensuring fast builds anywhere and for all team members.
When used with Docker Desktop, the [Builds view](/desktop/use-desktop/builds/)
works with Docker Build Cloud out-of-the-box. It shows information about your
builds and those initiated by your team members using the same builder,
enabling collaborative troubleshooting.
To use Docker Build Cloud without Docker Desktop, you must
[download and install](/build-cloud/setup/#use-docker-build-cloud-without-docker-desktop)
a version of Buildx with support for Docker Build Cloud (the `cloud` driver).
If you plan on building with Docker Build Cloud using the `docker compose
build` command, you also need a version of Docker Compose that supports Docker
Build Cloud.
### How does Docker Build Cloud work with Docker Compose?
Docker Compose works out of the box with Docker Build Cloud. Install the Docker
Build Cloud-compatible client (buildx) and it works with both commands.
### How many minutes are included in Docker Build Cloud Team plans?
Pricing details for Docker Build Cloud can be found on the [pricing page](https://www.docker.com/pricing?ref=Docs&refAction=DocsGuidesBuildCloudFaq).
### I’m a Docker personal user. Can I try Docker Build Cloud?
Docker subscribers (Pro, Team, Business) receive a set number of minutes each
month, shared across the account, to use Build Cloud.
If you do not have a Docker subscription, you may sign up for a free Personal
account and start a trial of Docker Build Cloud. Personal accounts are limited to a
single user.
For teams to receive the shared cache benefit, they must either be on a Docker
Team or Docker Business subscription.
### Does Docker Build Cloud support CI platforms? Does it work with GitHub Actions?
Yes, Docker Build Cloud can be used with various CI platforms including GitHub
Actions, CircleCI, Jenkins, and others. It can speed up your build pipelines,
which means less time spent waiting and context switching.
Docker Build Cloud can be used with GitHub Actions to automate your build,
test, and deployment pipeline. Docker provides a set of official GitHub Actions
that you can use in your workflows.
Using GitHub Actions with Docker Build Cloud is straightforward. With a
one-line change in your GitHub Actions configuration, everything else stays the
same. You don't need to create new pipelines. Learn more in the [CI
documentation](/build-cloud/ci/) for Docker Build Cloud.
<div id="dbc-lp-survey-anchor"></div>

View File

@@ -1,19 +0,0 @@
---
title: "Demo: set up and use Docker Build Cloud in development"
description: Learn how to use Docker Build Cloud for local builds.
keywords: docker build cloud, local development, cloud builds, multi-platform, build performance
weight: 20
---
With Docker Build Cloud, you can easily shift the build workload from local machines
to the cloud, helping you achieve faster build times, especially for multi-platform builds.
In this demo, you'll see:
- How to setup the builder locally
- How to use Docker Build Cloud with Docker Compose
- How the image cache speeds up builds for others on your team
{{< youtube-embed "oPGq2AP5OtQ" >}}
<div id="dbc-lp-survey-anchor"></div>

View File

@@ -0,0 +1,173 @@
---
title: "Docker Build Cloud: Reclaim your time with fast, multi-architecture builds"
linkTitle: Docker Build Cloud
description: |
Learn how to build and deploy Docker images to the cloud with Docker Build
Cloud.
summary: |
Build applications up to 39x faster using cloud-based resources, shared team
cache, and native multi-architecture support.
keywords: docker build cloud, cloud builds, multi-architecture, shared cache, ci/cd, build performance
aliases:
- /learning-paths/docker-build-cloud/
- /guides/docker-build-cloud/ci/
- /guides/docker-build-cloud/common-questions/
- /guides/docker-build-cloud/dev/
- /guides/docker-build-cloud/why/
params:
tags: [cicd]
image: images/learning-paths/build-cloud.png
time: 10 minutes
---
<!-- vale Vale.Spelling = NO -->
98% of developers spend up to an hour every day waiting for builds to finish
([Incredibuild: 2022 Big Dev Build Times](https://www.incredibuild.com/survey-report-2022)).
Heavy, complex builds can become a major roadblock for development teams,
slowing down both local development and CI/CD pipelines.
<!-- vale Vale.Spelling = YES -->
Docker Build Cloud speeds up image build times to improve developer
productivity, reduce frustrations, and help you shorten the release cycle.
## Who’s this for?
- Anyone who wants to tackle common causes of slow image builds: limited local
resources, slow emulation, and lack of build collaboration across a team.
- Developers working on older machines who want to build faster.
- Development teams working on the same repository who want to cut wait times
with a shared cache.
- Developers performing multi-architecture builds who don’t want to spend hours
configuring and rebuilding for emulators.
## What you’ll learn
- Building container images faster locally and in CI
- Accelerating builds for multi-platform images
- Reusing pre-built images to expedite workflows
## Tools integration
Works well with Docker Compose, GitHub Actions, and other CI solutions
<div id="dbc-lp-survey-anchor"></div>
## Why Docker Build Cloud?
Docker Build Cloud is a service that lets you build container images faster,
both locally and in CI. Builds run on cloud infrastructure optimally
dimensioned for your workloads, with no configuration required. The service
uses a remote build cache, ensuring fast builds anywhere and for all team
members.
Docker Build Cloud provides several benefits over local builds:
- Improved build speed
- Shared build cache
- Native multi-platform builds
There’s no need to worry about managing builders or infrastructure — simply
connect to your builders and start building. Each cloud builder provisioned to
an organization is completely isolated to a single Amazon EC2 instance, with a
dedicated EBS volume for build cache and encryption in transit. That means
there are no shared processes or data between cloud builders.
{{< youtube-embed "8AqKhEO2PQA" >}}
<div id="dbc-lp-survey-anchor"></div>
## Demo: set up and use Docker Build Cloud in development
With Docker Build Cloud, you can easily shift the build workload from local machines
to the cloud, helping you achieve faster build times, especially for multi-platform builds.
In this demo, you'll see:
- How to setup the builder locally
- How to use Docker Build Cloud with Docker Compose
- How the image cache speeds up builds for others on your team
{{< youtube-embed "oPGq2AP5OtQ" >}}
<div id="dbc-lp-survey-anchor"></div>
## Demo: Using Docker Build Cloud in CI
Docker Build Cloud can significantly decrease the time it takes for your CI builds
take to run, saving you time and money.
Since the builds run remotely, your CI runner can still use the Docker tooling CLI
without needing elevated permissions, making your builds more secure by default.
In this demo, you will see:
- How to integrate Docker Build Cloud into a variety of CI platforms
- How to use Docker Build Cloud in GitHub Actions to build multi-architecture images
- Speed differences between a workflow using Docker Build Cloud and a workflow running natively
- How to use Docker Build Cloud in a GitLab Pipeline
{{< youtube-embed "wvLdInoVBGg" >}}
<div id="dbc-lp-survey-anchor"></div>
## Common challenges and questions
#### Is Docker Build Cloud a standalone product or a part of Docker Desktop?
Docker Build Cloud is a service that can be used both with Docker Desktop and
standalone. It lets you build your container images faster, both locally and in
CI, with builds running on cloud infrastructure. The service uses a remote
build cache, ensuring fast builds anywhere and for all team members.
When used with Docker Desktop, the [Builds view](/desktop/use-desktop/builds/)
works with Docker Build Cloud out-of-the-box. It shows information about your
builds and those initiated by your team members using the same builder,
enabling collaborative troubleshooting.
To use Docker Build Cloud without Docker Desktop, you must
[download and install](/build-cloud/setup/#use-docker-build-cloud-without-docker-desktop)
a version of Buildx with support for Docker Build Cloud (the `cloud` driver).
If you plan on building with Docker Build Cloud using the `docker compose
build` command, you also need a version of Docker Compose that supports Docker
Build Cloud.
#### How does Docker Build Cloud work with Docker Compose?
Docker Compose works out of the box with Docker Build Cloud. Install the Docker
Build Cloud-compatible client (buildx) and it works with both commands.
#### How many minutes are included in Docker Build Cloud Team plans?
Pricing details for Docker Build Cloud can be found on the [pricing page](https://www.docker.com/pricing?ref=Docs&refAction=DocsGuidesBuildCloudFaq).
#### I’m a Docker personal user. Can I try Docker Build Cloud?
Docker subscribers (Pro, Team, Business) receive a set number of minutes each
month, shared across the account, to use Build Cloud.
If you do not have a Docker subscription, you may sign up for a free Personal
account and start a trial of Docker Build Cloud. Personal accounts are limited to a
single user.
For teams to receive the shared cache benefit, they must either be on a Docker
Team or Docker Business subscription.
#### Does Docker Build Cloud support CI platforms? Does it work with GitHub Actions?
Yes, Docker Build Cloud can be used with various CI platforms including GitHub
Actions, CircleCI, Jenkins, and others. It can speed up your build pipelines,
which means less time spent waiting and context switching.
Docker Build Cloud can be used with GitHub Actions to automate your build,
test, and deployment pipeline. Docker provides a set of official GitHub Actions
that you can use in your workflows.
Using GitHub Actions with Docker Build Cloud is straightforward. With a
one-line change in your GitHub Actions configuration, everything else stays the
same. You don't need to create new pipelines. Learn more in the [CI
documentation](/build-cloud/ci/) for Docker Build Cloud.
<div id="dbc-lp-survey-anchor"></div>

View File

@@ -1,28 +0,0 @@
---
title: Why Docker Build Cloud?
description: Learn how Docker Build Cloud makes your builds faster.
keywords: docker build cloud, cloud builds, shared cache, multi-architecture, build performance
weight: 10
---
Docker Build Cloud is a service that lets you build container images faster,
both locally and in CI. Builds run on cloud infrastructure optimally
dimensioned for your workloads, with no configuration required. The service
uses a remote build cache, ensuring fast builds anywhere and for all team
members.
Docker Build Cloud provides several benefits over local builds:
- Improved build speed
- Shared build cache
- Native multi-platform builds
There’s no need to worry about managing builders or infrastructure — simply
connect to your builders and start building. Each cloud builder provisioned to
an organization is completely isolated to a single Amazon EC2 instance, with a
dedicated EBS volume for build cache and encryption in transit. That means
there are no shared processes or data between cloud builders.
{{< youtube-embed "8AqKhEO2PQA" >}}
<div id="dbc-lp-survey-anchor"></div>

View File

@@ -1,63 +0,0 @@
---
title: Defining and running multi-container applications with Docker Compose
linkTitle: Docker Compose
summary: |
Simplify the process of defining, configuring, and running multi-container
Docker applications.
description: Learn how to use Docker Compose to define and run multi-container Docker applications.
keywords: docker compose, multi-container, compose file, services, orchestration, yaml
tags: [product-demo]
aliases:
- /learning-paths/docker-compose/
params:
image: images/learning-paths/compose.png
time: 10 minutes
resource_links:
- title: Overview of Docker Compose CLI
url: /reference/cli/docker/compose/
- title: Overview of Docker Compose
url: /compose/
- title: How Compose works
url: /compose/intro/compose-application-model/
- title: Using profiles with Compose
url: /compose/how-tos/profiles/
- title: Control startup and shutdown order with Compose
url: /compose/how-tos/startup-order/
- title: Compose Build Specification
url: /compose/compose-file/build/
---
Developers face challenges with multi-container Docker applications, including
complex configuration, dependency management, and maintaining consistent
environments. Networking, resource allocation, data persistence, logging, and
monitoring add to the difficulty. Security concerns and troubleshooting issues
further complicate the process, requiring effective tools and practices for
efficient management.
Docker Compose solves the problem of managing multi-container Docker
applications by providing a simple way to define, configure, and run all the
containers needed for an application using a single YAML file. This approach
helps developers to easily set up, share, and maintain consistent development,
testing, and production environments, ensuring that complex applications can be
deployed with all their dependencies and services properly configured and
orchestrated.
## What you’ll learn
- What Docker Compose is and what it does
- How to define services
- Use cases for Docker Compose
- How things would be different without Docker Compose
## Who’s this for?
- Developers and DevOps engineers who need to define, manage, and orchestrate
multi-container Docker applications efficiently across multiple environments.
- Development teams that want to increase productivity by streamlining
development workflows and reducing setup time.
## Tools integration
Works well with Docker CLI, CI/CD tools, and container orchestration tools.
<div id="compose-lp-survey-anchor"></div>

View File

@@ -1,78 +0,0 @@
---
title: Common challenges and questions
description: Explore common challenges and questions related to Docker Compose.
keywords: docker compose, faq, troubleshooting, environments, multi-container
weight: 30
---
<!-- vale Docker.HeadingLength = NO -->
### Do I need to maintain a separate Compose file for my development, testing, and staging environments?
You don't necessarily need to maintain entirely separate Compose files for your
development, testing, and staging environments. You can define all your
services in a single Compose file (`compose.yaml`). You can use profiles to
group service configurations specific to each environment (`dev`, `test`,
`staging`).
When you need to spin up an environment, you can activate the corresponding
profiles. For example, to set up the development environment:
```console
$ docker compose --profile dev up
```
This command starts only the services associated with the `dev` profile,
leaving the rest inactive.
For more information on using profiles, see [Using profiles with
Compose](/compose/how-tos/profiles/).
### How can I enforce the database service to start up before the frontend service?
Docker Compose ensures services start in a specific order by using the
`depends_on` property. This tells Compose to start the database service before
even attempting to launch the frontend service. This is crucial since
applications often rely on databases being ready for connections.
However, `depends_on` only guarantees the order, not that the database is fully
initialized. For a more robust approach, especially if your application relies
on a prepared database (e.g., after migrations), consider [health
checks](/reference/compose-file/services.md#healthcheck). Here, you can
configure the frontend to wait until the database passes its health check
before starting. This ensures the database is not only up but also ready to
handle requests.
For more information on setting the startup order of your services, see
[Control startup and shutdown order in Compose](/compose/how-tos/startup-order/).
### Can I use Compose to build a Docker image?
Yes, you can use Docker Compose to build Docker images. Docker Compose is a
tool for defining and running multi-container applications. Even if your
application isn't a multi-container application, Docker Compose can make it
easier to run by defining all the `docker run` options in a file.
To use Compose, you need a `compose.yaml` file. In this file, you can specify
the build context and Dockerfile for each service. When you run the command
`docker compose up --build`, Docker Compose will build the images for each
service and then start the containers.
For more information on building Docker images using Compose, see the [Compose
Build Specification](/compose/compose-file/build/).
### What is the difference between Docker Compose and Dockerfile?
A Dockerfile provides instructions to build a container image while a Compose
file defines your running containers. Quite often, a Compose file references a
Dockerfile to build an image to use for a particular service.
### What is the difference between the `docker compose up` and `docker compose run` commands?
The `docker compose up` command creates and starts all your services. It's
perfect for launching your development environment or running the entire
application. The `docker compose run` command focuses on individual services.
It starts a specified service along with its dependencies, allowing you to run
tests or perform one-off tasks within that container.
<div id="compose-lp-survey-anchor"></div>

View File

@@ -0,0 +1,160 @@
---
title: Defining and running multi-container applications with Docker Compose
linkTitle: Docker Compose
summary: |
Simplify the process of defining, configuring, and running multi-container
Docker applications.
description: Learn how to use Docker Compose to define and run multi-container Docker applications.
keywords: docker compose, multi-container, compose file, services, orchestration, yaml
aliases:
- /learning-paths/docker-compose/
- /guides/docker-compose/common-questions/
- /guides/docker-compose/setup/
- /guides/docker-compose/why/
params:
tags: [cicd]
image: images/learning-paths/compose.png
time: 10 minutes
---
Developers face challenges with multi-container Docker applications, including
complex configuration, dependency management, and maintaining consistent
environments. Networking, resource allocation, data persistence, logging, and
monitoring add to the difficulty. Security concerns and troubleshooting issues
further complicate the process, requiring effective tools and practices for
efficient management.
Docker Compose solves the problem of managing multi-container Docker
applications by providing a simple way to define, configure, and run all the
containers needed for an application using a single YAML file. This approach
helps developers to easily set up, share, and maintain consistent development,
testing, and production environments, ensuring that complex applications can be
deployed with all their dependencies and services properly configured and
orchestrated.
## What you’ll learn
- What Docker Compose is and what it does
- How to define services
- Use cases for Docker Compose
- How things would be different without Docker Compose
## Who’s this for?
- Developers and DevOps engineers who need to define, manage, and orchestrate
multi-container Docker applications efficiently across multiple environments.
- Development teams that want to increase productivity by streamlining
development workflows and reducing setup time.
## Tools integration
Works well with Docker CLI, CI/CD tools, and container orchestration tools.
<div id="compose-lp-survey-anchor"></div>
## Why Docker Compose?
Docker Compose is an essential tool for defining and running multi-container
Docker applications. Docker Compose simplifies the Docker experience, making it
easier for developers to create, manage, and deploy applications by using YAML
files to configure application services.
Docker Compose provides several benefits:
- Lets you define multi-container applications in a single YAML file.
- Ensures consistent environments across development, testing, and production.
- Manages the startup and linking of multiple containers effortlessly.
- Streamlines development workflows and reduces setup time.
- Ensures that each service runs in its own container, avoiding conflicts.
{{< youtube-embed 2EqarOM2V4U >}}
<div id="compose-lp-survey-anchor"></div>
## Demo: set up and use Docker Compose
This Docker Compose demo shows how to orchestrate a multi-container application
environment, streamlining development and deployment processes.
- Compare Docker Compose to the `docker run` command
- Configure a multi-container web app using a Compose file
- Run a multi-container web app using one command
{{< youtube-embed P5RBKmOLPH4 >}}
<div id="compose-lp-survey-anchor"></div>
## Common challenges and questions
<!-- vale Docker.HeadingLength = NO -->
#### Do I need to maintain a separate Compose file for my development, testing, and staging environments?
You don't necessarily need to maintain entirely separate Compose files for your
development, testing, and staging environments. You can define all your
services in a single Compose file (`compose.yaml`). You can use profiles to
group service configurations specific to each environment (`dev`, `test`,
`staging`).
When you need to spin up an environment, you can activate the corresponding
profiles. For example, to set up the development environment:
```console
$ docker compose --profile dev up
```
This command starts only the services associated with the `dev` profile,
leaving the rest inactive.
For more information on using profiles, see [Using profiles with
Compose](/compose/how-tos/profiles/).
#### How can I enforce the database service to start up before the frontend service?
Docker Compose ensures services start in a specific order by using the
`depends_on` property. This tells Compose to start the database service before
even attempting to launch the frontend service. This is crucial since
applications often rely on databases being ready for connections.
However, `depends_on` only guarantees the order, not that the database is fully
initialized. For a more robust approach, especially if your application relies
on a prepared database (e.g., after migrations), consider [health
checks](/reference/compose-file/services.md#healthcheck). Here, you can
configure the frontend to wait until the database passes its health check
before starting. This ensures the database is not only up but also ready to
handle requests.
For more information on setting the startup order of your services, see
[Control startup and shutdown order in Compose](/compose/how-tos/startup-order/).
#### Can I use Compose to build a Docker image?
Yes, you can use Docker Compose to build Docker images. Docker Compose is a
tool for defining and running multi-container applications. Even if your
application isn't a multi-container application, Docker Compose can make it
easier to run by defining all the `docker run` options in a file.
To use Compose, you need a `compose.yaml` file. In this file, you can specify
the build context and Dockerfile for each service. When you run the command
`docker compose up --build`, Docker Compose will build the images for each
service and then start the containers.
For more information on building Docker images using Compose, see the [Compose
Build Specification](/compose/compose-file/build/).
#### What is the difference between Docker Compose and Dockerfile?
A Dockerfile provides instructions to build a container image while a Compose
file defines your running containers. Quite often, a Compose file references a
Dockerfile to build an image to use for a particular service.
#### What is the difference between the `docker compose up` and `docker compose run` commands?
The `docker compose up` command creates and starts all your services. It's
perfect for launching your development environment or running the entire
application. The `docker compose run` command focuses on individual services.
It starts a specified service along with its dependencies, allowing you to run
tests or perform one-off tasks within that container.
<div id="compose-lp-survey-anchor"></div>

View File

@@ -1,17 +0,0 @@
---
title: "Demo: set up and use Docker Compose"
description: Learn how to get started with Docker Compose.
keywords: docker compose, getting started, multi-container, demo, orchestration
weight: 20
---
This Docker Compose demo shows how to orchestrate a multi-container application
environment, streamlining development and deployment processes.
- Compare Docker Compose to the `docker run` command
- Configure a multi-container web app using a Compose file
- Run a multi-container web app using one command
{{< youtube-embed P5RBKmOLPH4 >}}
<div id="compose-lp-survey-anchor"></div>

View File

@@ -1,23 +0,0 @@
---
title: Why Docker Compose?
description: Learn how Docker Compose can help you simplify app development.
keywords: docker compose, multi-container, yaml, services, orchestration, application
weight: 10
---
Docker Compose is an essential tool for defining and running multi-container
Docker applications. Docker Compose simplifies the Docker experience, making it
easier for developers to create, manage, and deploy applications by using YAML
files to configure application services.
Docker Compose provides several benefits:
- Lets you define multi-container applications in a single YAML file.
- Ensures consistent environments across development, testing, and production.
- Manages the startup and linking of multiple containers effortlessly.
- Streamlines development workflows and reduces setup time.
- Ensures that each service runs in its own container, avoiding conflicts.
{{< youtube-embed 2EqarOM2V4U >}}
<div id="compose-lp-survey-anchor"></div>

View File

@@ -1,65 +0,0 @@
---
title: Securing your software supply chain with Docker Scout
linkTitle: Docker Scout
summary: |
Enhance container security by automating vulnerability detection and
remediation.
description: |
Learn how to use Docker Scout to enhance container security by automating
vulnerability detection and remediation, ensuring compliance, and protecting
your development workflow.
keywords: docker scout, container security, vulnerability scanning, sbom, supply chain, remediation
tags: [product-demo]
aliases:
- /learning-paths/docker-scout/
params:
image: images/learning-paths/scout.png
time: 20 minutes
resource_links:
- title: Docker Scout overview
url: /scout/
- title: Docker Scout quickstart
url: /scout/quickstart/
- title: Install Docker Scout
url: /scout/install/
---
When container images are insecure, significant risks can arise. Around 60% of
organizations have reported experiencing at least one security breach or
vulnerability incident within a year, [resulting in operational
disruption][CSA]. These incidents often result in considerable downtime, with
44% of affected companies experiencing over an hour of downtime per event. The
financial impact is substantial, with [the average data breach cost reaching
$4.45 million][IBM]. This highlights the critical importance of maintaining
robust container security measures.
Docker Scout enhances container security by providing automated vulnerability
detection and remediation, addressing insecure container images, and ensuring
compliance with security standards.
[CSA]: https://cloudsecurityalliance.org/blog/2023/09/21/2023-global-cloud-threat-report-cloud-attacks-are-lightning-fast
[IBM]: https://www.ibm.com/reports/data-breach
## What you'll learn
- Define Secure Software Supply Chain (SSSC)
- Review SBOMs and how to use them
- Detect and monitor vulnerabilities
## Tools integration
Works well with Docker Desktop, GitHub Actions, Jenkins, Kubernetes, and
other CI solutions.
## Who’s this for?
- DevOps engineers who need to integrate automated security checks into CI/CD
pipelines to enhance the security and efficiency of their workflows.
- Developers who want to use Docker Scout to identify and remediate
vulnerabilities early in the development process, ensuring the production of
secure container images.
- Security professionals who must enforce security compliance, conduct
vulnerability assessments, and ensure the overall security of containerized
applications.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,36 +0,0 @@
---
title: Attestations
keywords: build, attestations, sbom, provenance, metadata
description: |
Introduction to SBOM and provenance attestations with Docker Build,
what they are, and why they exist
weight: 50
---
{{< youtube-embed qOzcycbTs4o >}}
[Build attestations](/manuals/build/metadata/attestations/_index.md) give you
detailed information about how an image was built and what it contains. These
attestations, generated by BuildKit during build-time, attach to the final
image as metadata, allowing you to inspect an image to see its origin, creator,
and contents. This information helps you make informed decisions about the
security and impact of the image on your supply chain.
Docker Scout uses these attestations to evaluate the image's security and
supply chain posture, and to provide remediation recommendations for issues. If
issues are detected, such as missing or outdated attestations, Docker Scout can
guide you on how to add or update them, ensuring compliance and improving
visibility into the image's security status.
There are two key types of attestations:
- SBOM, which lists the software artifacts within the image.
- Provenance, which details how the image was built.
You can create attestations by using `docker buildx build` with the
`--provenance` and `--sbom` flags. Attestations attach to the image index,
allowing you to inspect them without pulling the entire image. Docker Scout
leverages this metadata to give you more precise recommendations and better
control over your image's security.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,61 +0,0 @@
---
title: Common challenges and questions
description: Explore common challenges and questions related to Docker Scout.
keywords: docker scout, faq, container security, vulnerability scanning, troubleshooting
---
<!-- vale Docker.HeadingLength = NO -->
### How is Docker Scout different from other security tools?
Docker Scout takes a broader approach to container security compared to
third-party security tools. Third-party security tools, if they offer
remediation guidance at all, miss the mark on their limited scope of
application security posture within the software supply chain, and often
limited guidance when it comes to suggested fixes. Such tools have either
limitations on runtime monitoring or no runtime protection at all. When they do
offer runtime monitoring, it’s limited in its adherence to key policies.
Third-party security tools offer a limited scope of policy evaluation for
Docker-specific builds. By focusing on the entire software supply chain,
providing actionable guidance, and offering comprehensive runtime protection
with strong policy enforcement, Docker Scout goes beyond just identifying
vulnerabilities in your containers. It helps you build secure applications from
the ground up.
### Can I use Docker Scout with external registries other than Docker Hub?
You can use Scout with registries other than Docker Hub. Integrating Docker Scout
with third-party container registries enables Docker Scout to run image
analysis on those repositories so that you can get insights into the
composition of those images even if they aren't hosted on Docker Hub.
The following container registry integrations are available:
- Artifactory
- Amazon Elastic Container Registry
- Azure Container Registry
Learn more about configuring Scout with your registries in [Integrating Docker Scout with third-party registries](/scout/integrations/#container-registries).
### Does Docker Scout CLI come by default with Docker Desktop?
Yes, the Docker Scout CLI plugin comes pre-installed with Docker Desktop.
### Is it possible to run `docker scout` commands on a Linux system without Docker Desktop?
If you run Docker Engine without Docker Desktop, Docker Scout doesn't come
pre-installed, but you can [install it as a standalone binary](/scout/install/).
### How is Docker Scout using an SBOM?
An SBOM, or software bill of materials, is a list of ingredients that make up
software components. [Docker Scout uses SBOMs](/scout/concepts/sbom/) to
determine the components that are used in a Docker image. When you analyze an
image, Docker Scout will either use the SBOM that is attached to the image (as
an attestation), or generate an SBOM on the fly by analyzing the contents of
the image.
The SBOM is cross-referenced with the advisory database to determine if any of
the components in the image have known vulnerabilities.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,22 +0,0 @@
---
title: Docker Scout demo
linkTitle: Demo
description: Learn about Docker Scout's powerful features for enhanced supply chain security.
keywords: docker scout, demo, supply chain, vulnerability scanning, container security
weight: 20
---
{{< youtube-embed "TkLwJ0p46W8" >}}
Docker Scout has powerful features for enhancing containerized application
security and ensuring a robust software supply chain.
- Define vulnerability remediation
- Discuss why remediation is essential to maintain the security and integrity
of containerized applications
- Discuss common vulnerabilities
- Implement remediation techniques: updating base images, applying patches,
removing unnecessary packages
- Verify and validate remediation efforts using Docker Scout
<div id="scout-lp-survey-anchor"></div>

View File

@@ -0,0 +1,325 @@
---
title: Securing your software supply chain with Docker Scout
linkTitle: Docker Scout
summary: |
Enhance container security by automating vulnerability detection and
remediation.
description: |
Learn how to use Docker Scout to enhance container security by automating
vulnerability detection and remediation, ensuring compliance, and protecting
your development workflow.
keywords: docker scout, container security, vulnerability scanning, sbom, supply chain, remediation
aliases:
- /learning-paths/docker-scout/
- /scout/concepts/s3c/
- /scout/concepts/sbom/
- /guides/docker-scout/attestations/
- /guides/docker-scout/common-questions/
- /guides/docker-scout/demo/
- /guides/docker-scout/remediation/
- /guides/docker-scout/s3c/
- /guides/docker-scout/sbom/
- /guides/docker-scout/why/
params:
tags: [security]
image: images/learning-paths/scout.png
time: 20 minutes
---
When container images are insecure, significant risks can arise. Around 60% of
organizations have reported experiencing at least one security breach or
vulnerability incident within a year, [resulting in operational
disruption][CSA]. These incidents often result in considerable downtime, with
44% of affected companies experiencing over an hour of downtime per event. The
financial impact is substantial, with [the average data breach cost reaching
$4.45 million][IBM]. This highlights the critical importance of maintaining
robust container security measures.
Docker Scout enhances container security by providing automated vulnerability
detection and remediation, addressing insecure container images, and ensuring
compliance with security standards.
[CSA]: https://cloudsecurityalliance.org/blog/2023/09/21/2023-global-cloud-threat-report-cloud-attacks-are-lightning-fast
[IBM]: https://www.ibm.com/reports/data-breach
## What you'll learn
- Define Secure Software Supply Chain (SSSC)
- Review SBOMs and how to use them
- Detect and monitor vulnerabilities
## Tools integration
Works well with Docker Desktop, GitHub Actions, Jenkins, Kubernetes, and
other CI solutions.
## Who’s this for?
- DevOps engineers who need to integrate automated security checks into CI/CD
pipelines to enhance the security and efficiency of their workflows.
- Developers who want to use Docker Scout to identify and remediate
vulnerabilities early in the development process, ensuring the production of
secure container images.
- Security professionals who must enforce security compliance, conduct
vulnerability assessments, and ensure the overall security of containerized
applications.
<div id="scout-lp-survey-anchor"></div>
## Why Docker Scout?
{{< youtube-embed "-omsQ7Uqyc4" >}}
Organizations face significant challenges from data breaches,
including financial losses, operational disruptions, and long-term damage to
brand reputation and customer trust. Docker Scout addresses critical problems
such as identifying insecure container images, preventing security breaches,
and reducing the risk of operational downtime due to vulnerabilities.
Docker Scout provides several benefits:
- Secure and trusted content
- A system of record for your Software Development Lifecycle (SDLC)
- Continuous security posture improvement
Docker Scout offers automated vulnerability detection and remediation, helping
organizations identify and fix security issues in container images early in the
development process. It also integrates with popular development tools like
Docker Desktop and GitHub Actions, providing seamless security management and
compliance checks within existing workflows.
<div id="scout-lp-survey-anchor"></div>
## Docker Scout demo
{{< youtube-embed "TkLwJ0p46W8" >}}
Docker Scout has powerful features for enhancing containerized application
security and ensuring a robust software supply chain.
- Define vulnerability remediation
- Discuss why remediation is essential to maintain the security and integrity
of containerized applications
- Discuss common vulnerabilities
- Implement remediation techniques: updating base images, applying patches,
removing unnecessary packages
- Verify and validate remediation efforts using Docker Scout
<div id="scout-lp-survey-anchor"></div>
## Software supply chain security
{{< youtube-embed YzNK6E7APv0 >}}
The term "software supply chain" refers to the end-to-end process of developing
and delivering software, from the development to deployment and maintenance.
Software supply chain security, or "S3C" for short, is the practice for
protecting the components and processes of the supply chain.
S3C is a fundamental change in how organizations approach software security.
Traditionally in the software industry, security and compliance has been mostly
an afterthought, left to the software delivery or release phase. With S3C,
security is integrated into the entire software development lifecycle, from the
inner loop of development and testing, to the outer loop of shipping and
monitoring.
Following industry best practices for software supply chain conduct is
important because it helps organizations protect their software from security
threats, compliance risks, and other vulnerabilities. Implementing a software
supply chain security framework improves visibility, collaboration, and
traceability of a project across stakeholders. This helps organizations detect,
respond to, and remediate threats more effectively.
### Securing the software supply chain
Building a secure software supply chain involves several key steps, such as:
- Identify the software components and dependencies you use to build and run
your applications.
- Automate security testing throughout the software development lifecycle.
- Monitor your software supply chain for security threats.
- Implement security policies that govern how software is built, and the
components it contains.
Managing the software supply chain is a complex task, especially in the modern
day where software is built using multiple components from different sources.
Organizations need to have a clear understanding of the software components
they use, and the security risks associated with them.
### How Docker Scout is different
Docker Scout is a platform designed to help organizations secure their software
supply chain. It provides tools and services for identifying and managing
software assets and policies, and automated remediation of security threats.
Unlike traditional security tools that focus on scheduled, point-in-time scans
at specific stages in the software development lifecycle, Docker Scout uses a
modern event-driven model that spans the entire software supply chain. This
means that when a new vulnerability affecting your images is disclosed, your
updated risk assessment is available within seconds, and earlier in the
development process.
Docker Scout works by analyzing the composition of your images to create a
Software Bill of Materials (SBOM). The SBOM is cross-referenced against the
security advisories to identify CVEs that affect your images. Docker Scout
integrates with [over 20 different security
advisories](/manuals/scout/deep-dive/advisory-db-sources.md), and updates its
vulnerability database in real-time. This ensures that your security posture is
represented using the latest available information.
<div id="scout-lp-survey-anchor"></div>
## Software Bill of Materials
{{< youtube-embed PbS4y7C7h4A >}}
A Bill of Materials (BOM) is a list of materials, parts, and the quantities of
each needed to manufacture a product. For example, a BOM for a computer might
list the motherboard, CPU, RAM, power supply, storage devices, case, and other
components, along with the quantities of each that are needed to build the
computer.
A Software Bill of Materials (SBOM) is a list of all the components that make
up a piece of software. This includes open source and third-party components,
as well as any custom code that has been written for the software. An SBOM is
similar to a BOM for a physical product, but for software.
In the context of software supply chain security, SBOMs can help with
identifying and mitigating security and compliance risks in software. By
knowing exactly what components are used in a piece of software, you can
quickly identify and patch vulnerabilities in your components, or determine if
a component is licensed in a way that is incompatible with your project.
### Contents of an SBOM
An SBOM typically includes the following information:
- The name of the software, such as the name of a library or framework, that
the SBOM describes.
- The version of the software.
- The license under which the software is distributed.
- A list of other components that the software depends on.
### How Docker Scout uses SBOMs
Docker Scout uses SBOMs to determine the components that are used in a Docker
image. When you analyze an image, Docker Scout will either use the SBOM that is
attached to the image as an attestation, or it will generate an SBOM on the fly
by analyzing the contents of the image.
The SBOM is cross-referenced with the [advisory database](/manuals/scout/deep-dive/advisory-db-sources.md)
to determine if any of the components in the image have known vulnerabilities.
<div id="scout-lp-survey-anchor"></div>
## Attestations
{{< youtube-embed qOzcycbTs4o >}}
[Build attestations](/manuals/build/metadata/attestations/_index.md) give you
detailed information about how an image was built and what it contains. These
attestations, generated by BuildKit during build-time, attach to the final
image as metadata, allowing you to inspect an image to see its origin, creator,
and contents. This information helps you make informed decisions about the
security and impact of the image on your supply chain.
Docker Scout uses these attestations to evaluate the image's security and
supply chain posture, and to provide remediation recommendations for issues. If
issues are detected, such as missing or outdated attestations, Docker Scout can
guide you on how to add or update them, ensuring compliance and improving
visibility into the image's security status.
There are two key types of attestations:
- SBOM, which lists the software artifacts within the image.
- Provenance, which details how the image was built.
You can create attestations by using `docker buildx build` with the
`--provenance` and `--sbom` flags. Attestations attach to the image index,
allowing you to inspect them without pulling the entire image. Docker Scout
leverages this metadata to give you more precise recommendations and better
control over your image's security.
<div id="scout-lp-survey-anchor"></div>
## Remediation
{{< youtube-embed jM9zLBf8M-8 >}}
Docker Scout's [remediation feature](/manuals/scout/policy/remediation.md)
helps you address supply chain and security issues by offering tailored
recommendations based on policy evaluations. These recommendations guide you in
improving policy compliance or enhancing image metadata, allowing Docker Scout
to perform more accurate evaluations in the future.
You can use this feature to ensure that your base images are up-to-date and
that your supply chain attestations are complete. When a violation occurs,
Docker Scout provides recommended fixes, such as updating your base image or
adding missing attestations. If there isn’t enough information to determine
compliance, Docker Scout suggests actions to help resolve the issue.
In the Docker Scout Dashboard, you can view and act on these recommendations by
reviewing violations or compliance uncertainties. With integrations like
GitHub, you can even automate updates, directly fixing issues from the
dashboard.
<div id="scout-lp-survey-anchor"></div>
## Common challenges and questions
<!-- vale Docker.HeadingLength = NO -->
#### How is Docker Scout different from other security tools?
Docker Scout takes a broader approach to container security compared to
third-party security tools. Third-party security tools, if they offer
remediation guidance at all, miss the mark on their limited scope of
application security posture within the software supply chain, and often
limited guidance when it comes to suggested fixes. Such tools have either
limitations on runtime monitoring or no runtime protection at all. When they do
offer runtime monitoring, it’s limited in its adherence to key policies.
Third-party security tools offer a limited scope of policy evaluation for
Docker-specific builds. By focusing on the entire software supply chain,
providing actionable guidance, and offering comprehensive runtime protection
with strong policy enforcement, Docker Scout goes beyond just identifying
vulnerabilities in your containers. It helps you build secure applications from
the ground up.
#### Can I use Docker Scout with external registries other than Docker Hub?
You can use Scout with registries other than Docker Hub. Integrating Docker Scout
with third-party container registries enables Docker Scout to run image
analysis on those repositories so that you can get insights into the
composition of those images even if they aren't hosted on Docker Hub.
The following container registry integrations are available:
- Artifactory
- Amazon Elastic Container Registry
- Azure Container Registry
Learn more about configuring Scout with your registries in [Integrating Docker Scout with third-party registries](/scout/integrations/#container-registries).
#### Does Docker Scout CLI come by default with Docker Desktop?
Yes, the Docker Scout CLI plugin comes pre-installed with Docker Desktop.
#### Is it possible to run `docker scout` commands on a Linux system without Docker Desktop?
If you run Docker Engine without Docker Desktop, Docker Scout doesn't come
pre-installed, but you can [install it as a standalone binary](/scout/install/).
#### How is Docker Scout using an SBOM?
An SBOM, or software bill of materials, is a list of ingredients that make up
software components. [Docker Scout uses SBOMs](/scout/concepts/sbom/) to
determine the components that are used in a Docker image. When you analyze an
image, Docker Scout will either use the SBOM that is attached to the image (as
an attestation), or generate an SBOM on the fly by analyzing the contents of
the image.
The SBOM is cross-referenced with the advisory database to determine if any of
the components in the image have known vulnerabilities.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,27 +0,0 @@
---
title: Remediation
description: Learn how Docker Scout can help you improve your software quality automatically, using remediation
keywords: scout, supply chain, security, remediation, automation
weight: 60
---
{{< youtube-embed jM9zLBf8M-8 >}}
Docker Scout's [remediation feature](/manuals/scout/policy/remediation.md)
helps you address supply chain and security issues by offering tailored
recommendations based on policy evaluations. These recommendations guide you in
improving policy compliance or enhancing image metadata, allowing Docker Scout
to perform more accurate evaluations in the future.
You can use this feature to ensure that your base images are up-to-date and
that your supply chain attestations are complete. When a violation occurs,
Docker Scout provides recommended fixes, such as updating your base image or
adding missing attestations. If there isn’t enough information to determine
compliance, Docker Scout suggests actions to help resolve the issue.
In the Docker Scout Dashboard, you can view and act on these recommendations by
reviewing violations or compliance uncertainties. With integrations like
GitHub, you can even automate updates, directly fixing issues from the
dashboard.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,68 +0,0 @@
---
title: Software supply chain security
description: Learn about software supply chain security (S3C), what it means, and why it is important.
keywords: docker scout, secure, software, supply, chain, security, sssc, sscs, s3c
aliases:
- /scout/concepts/s3c/
weight: 30
---
{{< youtube-embed YzNK6E7APv0 >}}
The term "software supply chain" refers to the end-to-end process of developing
and delivering software, from the development to deployment and maintenance.
Software supply chain security, or "S3C" for short, is the practice for
protecting the components and processes of the supply chain.
S3C is a fundamental change in how organizations approach software security.
Traditionally in the software industry, security and compliance has been mostly
an afterthought, left to the software delivery or release phase. With S3C,
security is integrated into the entire software development lifecycle, from the
inner loop of development and testing, to the outer loop of shipping and
monitoring.
Following industry best practices for software supply chain conduct is
important because it helps organizations protect their software from security
threats, compliance risks, and other vulnerabilities. Implementing a software
supply chain security framework improves visibility, collaboration, and
traceability of a project across stakeholders. This helps organizations detect,
respond to, and remediate threats more effectively.
## Securing the software supply chain
Building a secure software supply chain involves several key steps, such as:
- Identify the software components and dependencies you use to build and run
your applications.
- Automate security testing throughout the software development lifecycle.
- Monitor your software supply chain for security threats.
- Implement security policies that govern how software is built, and the
components it contains.
Managing the software supply chain is a complex task, especially in the modern
day where software is built using multiple components from different sources.
Organizations need to have a clear understanding of the software components
they use, and the security risks associated with them.
## How Docker Scout is different
Docker Scout is a platform designed to help organizations secure their software
supply chain. It provides tools and services for identifying and managing
software assets and policies, and automated remediation of security threats.
Unlike traditional security tools that focus on scheduled, point-in-time scans
at specific stages in the software development lifecycle, Docker Scout uses a
modern event-driven model that spans the entire software supply chain. This
means that when a new vulnerability affecting your images is disclosed, your
updated risk assessment is available within seconds, and earlier in the
development process.
Docker Scout works by analyzing the composition of your images to create a
Software Bill of Materials (SBOM). The SBOM is cross-referenced against the
security advisories to identify CVEs that affect your images. Docker Scout
integrates with [over 20 different security
advisories](/manuals/scout/deep-dive/advisory-db-sources.md), and updates its
vulnerability database in real-time. This ensures that your security posture is
represented using the latest available information.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,49 +0,0 @@
---
title: Software Bill of Materials
description: Learn about Software Bill of Materials (SBOM) and how Docker Scout uses it.
keywords: scout, sbom, software bill of materials, analysis, composition
aliases:
- /scout/concepts/sbom/
weight: 40
---
{{< youtube-embed PbS4y7C7h4A >}}
A Bill of Materials (BOM) is a list of materials, parts, and the quantities of
each needed to manufacture a product. For example, a BOM for a computer might
list the motherboard, CPU, RAM, power supply, storage devices, case, and other
components, along with the quantities of each that are needed to build the
computer.
A Software Bill of Materials (SBOM) is a list of all the components that make
up a piece of software. This includes open source and third-party components,
as well as any custom code that has been written for the software. An SBOM is
similar to a BOM for a physical product, but for software.
In the context of software supply chain security, SBOMs can help with
identifying and mitigating security and compliance risks in software. By
knowing exactly what components are used in a piece of software, you can
quickly identify and patch vulnerabilities in your components, or determine if
a component is licensed in a way that is incompatible with your project.
## Contents of an SBOM
An SBOM typically includes the following information:
- The name of the software, such as the name of a library or framework, that
the SBOM describes.
- The version of the software.
- The license under which the software is distributed.
- A list of other components that the software depends on.
## How Docker Scout uses SBOMs
Docker Scout uses SBOMs to determine the components that are used in a Docker
image. When you analyze an image, Docker Scout will either use the SBOM that is
attached to the image as an attestation, or it will generate an SBOM on the fly
by analyzing the contents of the image.
The SBOM is cross-referenced with the [advisory database](/manuals/scout/deep-dive/advisory-db-sources.md)
to determine if any of the components in the image have known vulnerabilities.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,28 +0,0 @@
---
title: Why Docker Scout?
description: Learn how Docker Scout can help you secure your supply chain.
keywords: docker scout, supply chain security, vulnerability detection, sbom, container security
weight: 10
---
{{< youtube-embed "-omsQ7Uqyc4" >}}
Organizations face significant challenges from data breaches,
including financial losses, operational disruptions, and long-term damage to
brand reputation and customer trust. Docker Scout addresses critical problems
such as identifying insecure container images, preventing security breaches,
and reducing the risk of operational downtime due to vulnerabilities.
Docker Scout provides several benefits:
- Secure and trusted content
- A system of record for your Software Development Lifecycle (SDLC)
- Continuous security posture improvement
Docker Scout offers automated vulnerability detection and remediation, helping
organizations identify and fix security issues in container images early in the
development process. It also integrates with popular development tools like
Docker Desktop and GitHub Actions, providing seamless security management and
compliance checks within existing workflows.
<div id="scout-lp-survey-anchor"></div>

View File

@@ -1,32 +0,0 @@
---
title: .NET language-specific guide
linkTitle: C# (.NET)
description: Containerize and develop .NET apps using Docker
summary: |
Learn how to containerize .NET applications using Docker.
keywords: getting started, .net
aliases:
- /language/dotnet/
- /guides/language/dotnet/
- /guides/dotnet/configure-ci-cd/
- /language/dotnet/configure-ci-cd/
- /guides/language/dotnet/configure-ci-cd/
- /guides/dotnet/deploy/
- /language/dotnet/deploy/
- /guides/language/dotnet/deploy/
languages: [c-sharp]
params:
time: 20 minutes
toc_min: 1
toc_max: 2
---
The .NET getting started guide teaches you how to create a containerized .NET application using Docker. In this guide, you'll learn how to:
- Containerize and run a .NET application
- Set up a local environment to develop a .NET application using containers
- Run tests for a .NET application using containers
After completing the .NET getting started modules, you should be able to containerize your own .NET application based on the examples and instructions provided in this guide.
Start by containerizing an existing .NET application.

View File

@@ -1,364 +0,0 @@
---
title: Containerize a .NET application
linkTitle: Containerize your app
weight: 10
keywords: .net, containerize, initialize
description: Learn how to containerize an ASP.NET application.
aliases:
- /language/dotnet/build-images/
- /language/dotnet/run-containers/
- /language/dotnet/containerize/
- /guides/language/dotnet/containerize/
---
## Prerequisites
* You have installed the latest version of [Docker
Desktop](/get-started/get-docker.md).
* You have a [git client](https://git-scm.com/downloads). The examples in this
section use a command-line based git client, but you can use any client.
## Overview
This section walks you through containerizing and running a .NET
application.
## Get the sample applications
In this guide, you will use a pre-built .NET application. The application is
similar to the application built in the Docker Blog article, [Building a
Multi-Container .NET App Using Docker
Desktop](https://www.docker.com/blog/building-multi-container-net-app-using-docker-desktop/).
Open a terminal, change directory to a directory that you want to work in, and
run the following command to clone the repository.
```console
$ git clone https://github.com/docker/docker-dotnet-sample
```
## Create Docker assets
Now that you have an application, you can create the necessary Docker assets to containerize it. You can choose between using the official .NET images or Docker Hardened Images (DHI).
> [!TIP]
>
> [Gordon](/ai/gordon/), Docker's AI assistant, can generate Docker assets for your project. Ask Gordon to create a Dockerfile, Compose file, and `.dockerignore` tailored to your application.
> [Docker Hardened Images (DHIs)](https://docs.docker.com/dhi/) are minimal, secure, and production-ready container base and application images maintained by Docker. DHI images are recommended for better security—they are designed to reduce vulnerabilities and simplify compliance.
{{< tabs >}}
{{< tab name="Using Docker Hardened Images" >}}
Docker Hardened Images (DHIs) for .NET are available in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/aspnetcore). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
1. Sign in to the DHI registry:
```console
$ docker login dhi.io
```
2. Pull the .NET SDK DHI (check the catalog for available versions):
```console
$ docker pull dhi.io/dotnet:10-sdk
```
3. Pull the ASP.NET Core runtime DHI (check the catalog for available versions):
```console
$ docker pull dhi.io/aspnetcore:10
```
Create the following files in your `docker-dotnet-sample` directory.
```dockerfile {collapse=true,title=Dockerfile}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM dhi.io/aspnetcore:10 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
> [!NOTE]
>
> DHI runtime images already run as a non-root user (`nonroot`, UID 65532), so there's no need to create a user or specify `USER` in your Dockerfile. This reduces the attack surface and simplifies your configuration.
```yaml {collapse=true,title=compose.yaml}
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
```
```text {collapse=true,title=".dockerignore"}
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
```
{{< /tab >}}
{{< tab name="Using the official .NET 10 image" >}}
Create the following files in your `docker-dotnet-sample` directory.
```dockerfile {collapse=true,title=Dockerfile}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
```yaml {collapse=true,title=compose.yaml}
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
```
```text {collapse=true,title=".dockerignore"}
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
```
{{< /tab >}}
{{< /tabs >}}
You should now have the following contents in your `docker-dotnet-sample`
directory.
```text
├── docker-dotnet-sample/
│ ├── .git/
│ ├── src/
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── Dockerfile
│ └── README.md
```
To learn more about the files, see the following:
- [Dockerfile](/reference/dockerfile.md)
- [.dockerignore](/reference/dockerfile.md#dockerignore-file)
- [compose.yaml](/reference/compose-file/_index.md)
## Run the application
Inside the `docker-dotnet-sample` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application.
In the terminal, press `ctrl`+`c` to stop the application.
### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `docker-dotnet-sample` directory, run the following command
in a terminal.
```console
$ docker compose up --build -d
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application.
In the terminal, run the following command to stop the application.
```console
$ docker compose down
```
For more information about Compose commands, see the [Compose CLI
reference](/reference/cli/docker/compose/).
## Summary
In this section, you learned how you can containerize and run your .NET
application using Docker.
Related information:
- [Dockerfile reference](/reference/dockerfile.md)
- [.dockerignore file reference](/reference/dockerfile.md#dockerignore-file)
- [Docker Compose overview](/manuals/compose/_index.md)
- [Docker Hardened Images](/dhi/)
## Next steps
In the next section, you'll learn how you can develop your application using
Docker containers.

View File

@@ -1,425 +0,0 @@
---
title: Use containers for .NET development
linkTitle: Develop your app
weight: 20
keywords: .net, development
description: Learn how to develop your .NET application locally using containers.
aliases:
- /language/dotnet/develop/
- /guides/language/dotnet/develop/
---
## Prerequisites
Complete [Containerize a .NET application](containerize.md).
## Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Adding a local database and persisting data
- Configuring Compose to automatically update your running Compose services as you edit and save your code
- Creating a development container that contains the .NET Core SDK tools and dependencies
## Update the application
This section uses a different branch of the `docker-dotnet-sample` repository
that contains an updated .NET application. The updated application is on the
`add-db` branch of the repository you cloned in [Containerize a .NET
application](containerize.md).
To get the updated code, you need to checkout the `add-db` branch. For the changes you made in [Containerize a .NET application](containerize.md), for this section, you can stash them. In a terminal, run the following commands in the `docker-dotnet-sample` directory.
1. Stash any previous changes.
```console
$ git stash -u
```
2. Check out the new branch with the updated application.
```console
$ git checkout add-db
```
In the `add-db` branch, only the .NET application has been updated. None of the Docker assets have been updated yet.
You should now have the following in your `docker-dotnet-sample` directory.
```text
├── docker-dotnet-sample/
│ ├── .git/
│ ├── src/
│ │ ├── Data/
│ │ ├── Models/
│ │ ├── Pages/
│ │ ├── Properties/
│ │ ├── wwwroot/
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── myWebApp.csproj
│ │ └── Program.cs
│ ├── tests/
│ │ ├── tests.csproj
│ │ ├── UnitTest1.cs
│ │ └── Usings.cs
│ ├── .dockerignore
│ ├── .gitignore
│ ├── compose.yaml
│ ├── Dockerfile
│ └── README.md
```
## Add a local database and persist data
You can use containers to set up local services, like a database. In this section, you'll update the `compose.yaml` file to define a database service and a volume to persist data.
Open the `compose.yaml` file in an IDE or text editor. You'll notice it
already contains commented-out instructions for a PostgreSQL database and volume.
Open `docker-dotnet-sample/src/appsettings.json` in an IDE or text editor. You'll
notice the connection string with all the database information. The
`compose.yaml` already contains this information, but it's commented out.
Uncomment the database instructions in the `compose.yaml` file.
The following is the updated `compose.yaml` file.
```yaml {hl_lines="8-33"}
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
```
> [!NOTE]
>
> To learn more about the instructions in the Compose file, see [Compose file
> reference](/reference/compose-file/).
Before you run the application using Compose, notice that this Compose file uses
`secrets` and specifies a `password.txt` file to hold the database's password.
You must create this file as it's not included in the source repository.
In the `docker-dotnet-sample` directory, create a new directory named `db` and
inside that directory create a file named `password.txt`. Open `password.txt` in an IDE or text editor and add the following password. The password must be on a single line, with no additional lines in the file.
```text
example
```
Save and close the `password.txt` file.
You should now have the following in your `docker-dotnet-sample` directory.
```text
├── docker-dotnet-sample/
│ ├── .git/
│ ├── db/
│ │ └── password.txt
│ ├── src/
│ ├── tests/
│ ├── .dockerignore
│ ├── .gitignore
│ ├── compose.yaml
│ ├── Dockerfile
│ └── README.md
```
Run the following command to start your application.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application with the text `Student name is`.
The application doesn't display a name because the database is empty. For this application, you need to access the database and then add records.
## Add records to the database
For the sample application, you must access the database directly to create sample records.
You can run commands inside the database container using the `docker exec`
command. Before running that command, you must get the ID of the database
container. Open a new terminal window and run the following command to list all
your running containers.
```console
$ docker container ls
```
You should see output like the following.
```console
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb36e310aa7e docker-dotnet-sample-server "dotnet myWebApp.dll" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp docker-dotnet-sample-server-1
39fdcf0aff7b postgres:18 "docker-entrypoint.s…" About a minute ago Up About a minute (healthy) 5432/tcp docker-dotnet-sample-db-1
```
In the previous example, the container ID is `39fdcf0aff7b`. Run the following command to connect to the postgres database in the container. Replace the container ID with your own container ID.
```console
$ docker exec -it 39fdcf0aff7b psql -d example -U postgres
```
And finally, insert a record into the database.
```console
example=# INSERT INTO "Students" ("ID", "LastName", "FirstMidName", "EnrollmentDate") VALUES (DEFAULT, 'Whale', 'Moby', '2013-03-20');
```
You should see output like the following.
```console
INSERT 0 1
```
Close the database connection and exit the container shell by running `exit`.
```console
example=# exit
```
## Verify that data persists in the database
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application with the text `Student name is Moby Whale`.
Press `ctrl+c` in the terminal to stop your application.
In the terminal, run `docker compose rm` to remove your containers and then run `docker compose up` to run your application again.
```console
$ docker compose rm
$ docker compose up --build
```
Refresh [http://localhost:8080](http://localhost:8080) in your browser and verify that the student name persisted, even after the containers were removed and ran again.
Press `ctrl+c` in the terminal to stop your application.
## Automatically update services
Use Compose Watch to automatically update your running Compose services as you edit and save your code. For more details about Compose Watch, see [Use Compose Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yaml` file in an IDE or text editor and then add the Compose Watch instructions. The following is the updated `compose.yaml` file.
```yaml {hl_lines="11-14"}
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
develop:
watch:
- action: rebuild
path: .
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Open a browser and verify that the application is running at [http://localhost:8080](http://localhost:8080).
Any changes to the application's source files on your local machine will now be
immediately reflected in the running container.
Open `docker-dotnet-sample/src/Pages/Index.cshtml` in an IDE or text editor and update the student name text on line 13 from `Student name is` to `Student name:`.
```diff
- <p>Student name is @Model.StudentName</p>
+ <p>Student name: @Model.StudentName</p>
```
Save the changes to `Index.cshtml` and then wait a few seconds for the application to rebuild. Refresh [http://localhost:8080](http://localhost:8080) in your browser and verify that the updated text appears.
Press `ctrl+c` in the terminal to stop your application.
## Create a development container
At this point, when you run your containerized application, it's using the .NET runtime image. While this small image is good for production, it lacks the SDK tools and dependencies you may need when developing. Also, during development, you may not need to run `dotnet publish`. You can use multi-stage builds to build stages for both development and production in the same Dockerfile. For more details, see [Multi-stage builds](/manuals/build/building/multi-stage.md).
Add a new development stage to your Dockerfile and update your `compose.yaml` file to use this stage for local development.
The following is the updated Dockerfile.
{{< tabs >}}
{{< tab name="Using Docker Hardened Images" >}}
```Dockerfile {hl_lines="10-13"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM dhi.io/dotnet:10-sdk AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM dhi.io/aspnetcore:10 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< tab name="Using the official .NET 10 image" >}}
```Dockerfile {hl_lines="10-13"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< /tabs >}}
The following is the updated `compose.yaml` file.
```yaml {hl_lines=[5,15,16]}
services:
server:
build:
context: .
target: development
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
develop:
watch:
- action: rebuild
path: .
environment:
- ASPNETCORE_ENVIRONMENT=Development
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
```
Your containerized application will now use the SDK image (either `dhi.io/dotnet:10-sdk` for DHI or `mcr.microsoft.com/dotnet/sdk:10.0-alpine` for official images), which includes development tools like `dotnet test`. Continue to the next section to learn how you can run `dotnet test`.
## Summary
In this section, you took a look at setting up your Compose file to add a local
database and persist data. You also learned how to use Compose Watch to automatically rebuild and run your container when you update your code. And finally, you learned how to create a development container that contains the SDK tools and dependencies needed for development.
Related information:
- [Compose file reference](/reference/compose-file/)
- [Compose file watch](/manuals/compose/how-tos/file-watch.md)
- [Multi-stage builds](/manuals/build/building/multi-stage.md)
## Next steps
In the next section, you'll learn how to run unit tests using Docker.

View File

@@ -0,0 +1,915 @@
---
title: .NET language-specific guide
linkTitle: C# (.NET)
description: Containerize and develop .NET apps using Docker
summary: |
Learn how to containerize .NET applications using Docker.
keywords: getting started, .net
aliases:
- /language/dotnet/
- /guides/language/dotnet/
- /language/dotnet/develop/
- /language/dotnet/run-tests/
- /language/dotnet/configure-ci-cd/
- /language/dotnet/deploy/
- /guides/dotnet/configure-ci-cd/
- /guides/dotnet/containerize/
- /guides/dotnet/deploy/
- /guides/dotnet/develop/
- /guides/dotnet/run-tests/
params:
tags: [languages]
time: 20 minutes
toc_min: 1
toc_max: 2
---
The .NET getting started guide teaches you how to create a containerized .NET application using Docker. In this guide, you'll learn how to:
- Containerize and run a .NET application
- Set up a local environment to develop a .NET application using containers
- Run tests for a .NET application using containers
After completing the .NET getting started modules, you should be able to containerize your own .NET application based on the examples and instructions provided in this guide.
Start by containerizing an existing .NET application.
## Containerize a .NET application
### Prerequisites
- You have installed the latest version of [Docker
Desktop](/get-started/get-docker.md).
- You have a [git client](https://git-scm.com/downloads). The examples in this
section use a command-line based git client, but you can use any client.
### Overview
This section walks you through containerizing and running a .NET
application.
### Get the sample applications
In this guide, you will use a pre-built .NET application. The application is
similar to the application built in the Docker Blog article, [Building a
Multi-Container .NET App Using Docker
Desktop](https://www.docker.com/blog/building-multi-container-net-app-using-docker-desktop/).
Open a terminal, change directory to a directory that you want to work in, and
run the following command to clone the repository.
```console
$ git clone https://github.com/docker/docker-dotnet-sample
```
### Create Docker assets
Now that you have an application, you can create the necessary Docker assets to containerize it. You can choose between using the official .NET images or Docker Hardened Images (DHI).
> [!TIP]
>
> [Gordon](/ai/gordon/), Docker's AI assistant, can generate Docker assets for your project. Ask Gordon to create a Dockerfile, Compose file, and `.dockerignore` tailored to your application.
> [Docker Hardened Images (DHIs)](https://docs.docker.com/dhi/) are minimal, secure, and production-ready container base and application images maintained by Docker. DHI images are recommended for better security—they are designed to reduce vulnerabilities and simplify compliance.
{{< tabs >}}
{{< tab name="Using Docker Hardened Images" >}}
Docker Hardened Images (DHIs) for .NET are available in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/aspnetcore). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
1. Sign in to the DHI registry:
```console
$ docker login dhi.io
```
2. Pull the .NET SDK DHI (check the catalog for available versions):
```console
$ docker pull dhi.io/dotnet:10-sdk
```
3. Pull the ASP.NET Core runtime DHI (check the catalog for available versions):
```console
$ docker pull dhi.io/aspnetcore:10
```
Create the following files in your `docker-dotnet-sample` directory.
```dockerfile {collapse=true,title=Dockerfile}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM dhi.io/aspnetcore:10 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
> [!NOTE]
>
> DHI runtime images already run as a non-root user (`nonroot`, UID 65532), so there's no need to create a user or specify `USER` in your Dockerfile. This reduces the attack surface and simplifies your configuration.
```yaml {collapse=true,title=compose.yaml}
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
```
```text {collapse=true,title=".dockerignore"}
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
```
{{< /tab >}}
{{< tab name="Using the official .NET 10 image" >}}
Create the following files in your `docker-dotnet-sample` directory.
```dockerfile {collapse=true,title=Dockerfile}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
```yaml {collapse=true,title=compose.yaml}
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
```
```text {collapse=true,title=".dockerignore"}
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
```
{{< /tab >}}
{{< /tabs >}}
You should now have the following contents in your `docker-dotnet-sample`
directory.
```text
├── docker-dotnet-sample/
│ ├── .git/
│ ├── src/
│ ├── .dockerignore
│ ├── compose.yaml
│ ├── Dockerfile
│ └── README.md
```
To learn more about the files, see the following:
- [Dockerfile](/reference/dockerfile.md)
- [.dockerignore](/reference/dockerfile.md#dockerignore-file)
- [compose.yaml](/reference/compose-file/_index.md)
### Run the application
Inside the `docker-dotnet-sample` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application.
In the terminal, press `ctrl`+`c` to stop the application.
#### Run the application in the background
You can run the application detached from the terminal by adding the `-d`
option. Inside the `docker-dotnet-sample` directory, run the following command
in a terminal.
```console
$ docker compose up --build -d
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application.
In the terminal, run the following command to stop the application.
```console
$ docker compose down
```
For more information about Compose commands, see the [Compose CLI
reference](/reference/cli/docker/compose/).
## Use containers for .NET development
### Prerequisites
Complete [Containerize a .NET application](./).
### Overview
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
- Adding a local database and persisting data
- Configuring Compose to automatically update your running Compose services as you edit and save your code
- Creating a development container that contains the .NET Core SDK tools and dependencies
### Update the application
This section uses a different branch of the `docker-dotnet-sample` repository
that contains an updated .NET application. The updated application is on the
`add-db` branch of the repository you cloned in [Containerize a .NET
application](./).
To get the updated code, you need to checkout the `add-db` branch. For the changes you made in [Containerize a .NET application](./), for this section, you can stash them. In a terminal, run the following commands in the `docker-dotnet-sample` directory.
1. Stash any previous changes.
```console
$ git stash -u
```
2. Check out the new branch with the updated application.
```console
$ git checkout add-db
```
In the `add-db` branch, only the .NET application has been updated. None of the Docker assets have been updated yet.
You should now have the following in your `docker-dotnet-sample` directory.
```text
├── docker-dotnet-sample/
│ ├── .git/
│ ├── src/
│ │ ├── Data/
│ │ ├── Models/
│ │ ├── Pages/
│ │ ├── Properties/
│ │ ├── wwwroot/
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── myWebApp.csproj
│ │ └── Program.cs
│ ├── tests/
│ │ ├── tests.csproj
│ │ ├── UnitTest1.cs
│ │ └── Usings.cs
│ ├── .dockerignore
│ ├── .gitignore
│ ├── compose.yaml
│ ├── Dockerfile
│ └── README.md
```
### Add a local database and persist data
You can use containers to set up local services, like a database. In this section, you'll update the `compose.yaml` file to define a database service and a volume to persist data.
Open the `compose.yaml` file in an IDE or text editor. You'll notice it
already contains commented-out instructions for a PostgreSQL database and volume.
Open `docker-dotnet-sample/src/appsettings.json` in an IDE or text editor. You'll
notice the connection string with all the database information. The
`compose.yaml` already contains this information, but it's commented out.
Uncomment the database instructions in the `compose.yaml` file.
The following is the updated `compose.yaml` file.
```yaml {hl_lines="8-33"}
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
```
> [!NOTE]
>
> To learn more about the instructions in the Compose file, see [Compose file
> reference](/reference/compose-file/).
Before you run the application using Compose, notice that this Compose file uses
`secrets` and specifies a `password.txt` file to hold the database's password.
You must create this file as it's not included in the source repository.
In the `docker-dotnet-sample` directory, create a new directory named `db` and
inside that directory create a file named `password.txt`. Open `password.txt` in an IDE or text editor and add the following password. The password must be on a single line, with no additional lines in the file.
```text
example
```
Save and close the `password.txt` file.
You should now have the following in your `docker-dotnet-sample` directory.
```text
├── docker-dotnet-sample/
│ ├── .git/
│ ├── db/
│ │ └── password.txt
│ ├── src/
│ ├── tests/
│ ├── .dockerignore
│ ├── .gitignore
│ ├── compose.yaml
│ ├── Dockerfile
│ └── README.md
```
Run the following command to start your application.
```console
$ docker compose up --build
```
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application with the text `Student name is`.
The application doesn't display a name because the database is empty. For this application, you need to access the database and then add records.
### Add records to the database
For the sample application, you must access the database directly to create sample records.
You can run commands inside the database container using the `docker exec`
command. Before running that command, you must get the ID of the database
container. Open a new terminal window and run the following command to list all
your running containers.
```console
$ docker container ls
```
You should see output like the following.
```console
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb36e310aa7e docker-dotnet-sample-server "dotnet myWebApp.dll" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp docker-dotnet-sample-server-1
39fdcf0aff7b postgres:18 "docker-entrypoint.s…" About a minute ago Up About a minute (healthy) 5432/tcp docker-dotnet-sample-db-1
```
In the previous example, the container ID is `39fdcf0aff7b`. Run the following command to connect to the postgres database in the container. Replace the container ID with your own container ID.
```console
$ docker exec -it 39fdcf0aff7b psql -d example -U postgres
```
And finally, insert a record into the database.
```console
example=# INSERT INTO "Students" ("ID", "LastName", "FirstMidName", "EnrollmentDate") VALUES (DEFAULT, 'Whale', 'Moby', '2013-03-20');
```
You should see output like the following.
```console
INSERT 0 1
```
Close the database connection and exit the container shell by running `exit`.
```console
example=# exit
```
### Verify that data persists in the database
Open a browser and view the application at [http://localhost:8080](http://localhost:8080). You should see a simple web application with the text `Student name is Moby Whale`.
Press `ctrl+c` in the terminal to stop your application.
In the terminal, run `docker compose rm` to remove your containers and then run `docker compose up` to run your application again.
```console
$ docker compose rm
$ docker compose up --build
```
Refresh [http://localhost:8080](http://localhost:8080) in your browser and verify that the student name persisted, even after the containers were removed and ran again.
Press `ctrl+c` in the terminal to stop your application.
### Automatically update services
Use Compose Watch to automatically update your running Compose services as you edit and save your code. For more details about Compose Watch, see [Use Compose Watch](/manuals/compose/how-tos/file-watch.md).
Open your `compose.yaml` file in an IDE or text editor and then add the Compose Watch instructions. The following is the updated `compose.yaml` file.
```yaml {hl_lines="11-14"}
services:
server:
build:
context: .
target: final
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
develop:
watch:
- action: rebuild
path: .
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
```
Run the following command to run your application with Compose Watch.
```console
$ docker compose watch
```
Open a browser and verify that the application is running at [http://localhost:8080](http://localhost:8080).
Any changes to the application's source files on your local machine will now be
immediately reflected in the running container.
Open `docker-dotnet-sample/src/Pages/Index.cshtml` in an IDE or text editor and update the student name text on line 13 from `Student name is` to `Student name:`.
```diff
- <p>Student name is @Model.StudentName</p>
+ <p>Student name: @Model.StudentName</p>
```
Save the changes to `Index.cshtml` and then wait a few seconds for the application to rebuild. Refresh [http://localhost:8080](http://localhost:8080) in your browser and verify that the updated text appears.
Press `ctrl+c` in the terminal to stop your application.
### Create a development container
At this point, when you run your containerized application, it's using the .NET runtime image. While this small image is good for production, it lacks the SDK tools and dependencies you may need when developing. Also, during development, you may not need to run `dotnet publish`. You can use multi-stage builds to build stages for both development and production in the same Dockerfile. For more details, see [Multi-stage builds](/manuals/build/building/multi-stage.md).
Add a new development stage to your Dockerfile and update your `compose.yaml` file to use this stage for local development.
The following is the updated Dockerfile.
{{< tabs >}}
{{< tab name="Using Docker Hardened Images" >}}
```Dockerfile {hl_lines="10-13"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM dhi.io/dotnet:10-sdk AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM dhi.io/aspnetcore:10 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< tab name="Using the official .NET 10 image" >}}
```Dockerfile {hl_lines="10-13"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< /tabs >}}
The following is the updated `compose.yaml` file.
```yaml {hl_lines=[5,15,16]}
services:
server:
build:
context: .
target: development
ports:
- 8080:8080
depends_on:
db:
condition: service_healthy
develop:
watch:
- action: rebuild
path: .
environment:
- ASPNETCORE_ENVIRONMENT=Development
db:
image: postgres:18
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
```
Your containerized application will now use the SDK image (either `dhi.io/dotnet:10-sdk` for DHI or `mcr.microsoft.com/dotnet/sdk:10.0-alpine` for official images), which includes development tools like `dotnet test`. Continue to the next section to learn how you can run `dotnet test`.
## Run .NET tests in a container
### Prerequisites
Complete all the previous sections of this guide, starting with [Containerize a .NET application](./).
### Overview
Testing is an essential part of modern software development. Testing can mean a
lot of things to different development teams. There are unit tests, integration
tests and end-to-end testing. In this guide you take a look at running your unit
tests in Docker when developing and when building.
### Run tests when developing locally
The sample application already has an xUnit test inside the `tests` directory. When developing locally, you can use Compose to run your tests.
Run the following command in the `docker-dotnet-sample` directory to run the tests inside a container.
```console
$ docker compose run --build --rm server dotnet test /source/tests
```
You should see output that contains the following.
```console
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net10.0/tests.dll (net10.0)
```
To learn more about the command, see [docker compose run](/reference/cli/docker/compose/run/).
### Run tests when building
To run your tests when building, you need to update your Dockerfile. You can create a new test stage that runs the tests, or run the tests in the existing build stage. For this guide, update the Dockerfile to run the tests in the build stage.
The following is the updated Dockerfile.
{{< tabs >}}
{{< tab name="Using Docker Hardened Images" >}}
```dockerfile {hl_lines="9"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
RUN dotnet test /source/tests
FROM dhi.io/dotnet:10-sdk AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM dhi.io/aspnetcore:10 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< tab name="Using the official .NET 10 image" >}}
```dockerfile {hl_lines="9"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
RUN dotnet test /source/tests
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< /tabs >}}
Run the following command to build an image using the build stage as the target and view the test results. Include `--progress=plain` to view the build output, `--no-cache` to ensure the tests always run, and `--target build` to target the build stage.
```console
$ docker build -t dotnet-docker-image-test --progress=plain --no-cache --target build .
```
You should see output containing the following.
```console
#11 [build 5/5] RUN dotnet test /source/tests
#11 1.564 Determining projects to restore...
#11 3.421 Restored /source/src/myWebApp.csproj (in 1.02 sec).
#11 19.42 Restored /source/tests/tests.csproj (in 17.05 sec).
#11 27.91 myWebApp -> /source/src/bin/Debug/net10.0/myWebApp.dll
#11 28.47 tests -> /source/tests/bin/Debug/net10.0/tests.dll
#11 28.49 Test run for /source/tests/bin/Debug/net10.0/tests.dll (.NETCoreApp,Version=v10.0)
#11 28.67 Microsoft (R) Test Execution Command Line Tool Version 17.3.3 (x64)
#11 28.67 Copyright (c) Microsoft Corporation. All rights reserved.
#11 28.68
#11 28.97 Starting test execution, please wait...
#11 29.03 A total of 1 test files matched the specified pattern.
#11 32.07
#11 32.08 Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net10.0/tests.dll (net10.0)
#11 DONE 32.2s
```
### Summary
In this section, you learned how to run tests when developing locally using Compose and how to run tests when building your image.
Related information:
- [docker compose run](/reference/cli/docker/compose/run/)

View File

@@ -1,146 +0,0 @@
---
title: Run .NET tests in a container
linkTitle: Run your tests
weight: 30
keywords: .NET, test
description: Learn how to run your .NET tests in a container.
aliases:
- /language/dotnet/run-tests/
- /guides/language/dotnet/run-tests/
---
## Prerequisites
Complete all the previous sections of this guide, starting with [Containerize a .NET application](containerize.md).
## Overview
Testing is an essential part of modern software development. Testing can mean a
lot of things to different development teams. There are unit tests, integration
tests and end-to-end testing. In this guide you take a look at running your unit
tests in Docker when developing and when building.
## Run tests when developing locally
The sample application already has an xUnit test inside the `tests` directory. When developing locally, you can use Compose to run your tests.
Run the following command in the `docker-dotnet-sample` directory to run the tests inside a container.
```console
$ docker compose run --build --rm server dotnet test /source/tests
```
You should see output that contains the following.
```console
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net10.0/tests.dll (net10.0)
```
To learn more about the command, see [docker compose run](/reference/cli/docker/compose/run/).
## Run tests when building
To run your tests when building, you need to update your Dockerfile. You can create a new test stage that runs the tests, or run the tests in the existing build stage. For this guide, update the Dockerfile to run the tests in the build stage.
The following is the updated Dockerfile.
{{< tabs >}}
{{< tab name="Using Docker Hardened Images" >}}
```dockerfile {hl_lines="9"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM dhi.io/dotnet:10-sdk AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
RUN dotnet test /source/tests
FROM dhi.io/dotnet:10-sdk AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM dhi.io/aspnetcore:10 AS final
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< tab name="Using the official .NET 10 image" >}}
```dockerfile {hl_lines="9"}
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG TARGETARCH
COPY . /source
WORKDIR /source/src
RUN --mount=type=cache,id=nuget,target=/root/.nuget/packages \
dotnet publish -a ${TARGETARCH/amd64/x64} --use-current-runtime --self-contained false -o /app
RUN dotnet test /source/tests
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS development
COPY . /source
WORKDIR /source/src
CMD dotnet run --no-launch-profile
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final
WORKDIR /app
COPY --from=build /app .
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser
ENTRYPOINT ["dotnet", "myWebApp.dll"]
```
{{< /tab >}}
{{< /tabs >}}
Run the following command to build an image using the build stage as the target and view the test results. Include `--progress=plain` to view the build output, `--no-cache` to ensure the tests always run, and `--target build` to target the build stage.
```console
$ docker build -t dotnet-docker-image-test --progress=plain --no-cache --target build .
```
You should see output containing the following.
```console
#11 [build 5/5] RUN dotnet test /source/tests
#11 1.564 Determining projects to restore...
#11 3.421 Restored /source/src/myWebApp.csproj (in 1.02 sec).
#11 19.42 Restored /source/tests/tests.csproj (in 17.05 sec).
#11 27.91 myWebApp -> /source/src/bin/Debug/net10.0/myWebApp.dll
#11 28.47 tests -> /source/tests/bin/Debug/net10.0/tests.dll
#11 28.49 Test run for /source/tests/bin/Debug/net10.0/tests.dll (.NETCoreApp,Version=v10.0)
#11 28.67 Microsoft (R) Test Execution Command Line Tool Version 17.3.3 (x64)
#11 28.67 Copyright (c) Microsoft Corporation. All rights reserved.
#11 28.68
#11 28.97 Starting test execution, please wait...
#11 29.03 A total of 1 test files matched the specified pattern.
#11 32.07
#11 32.08 Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: < 1 ms - /source/tests/bin/Debug/net10.0/tests.dll (net10.0)
#11 DONE 32.2s
```
## Summary
In this section, you learned how to run tests when developing locally using Compose and how to run tests when building your image.
Related information:
- [docker compose run](/reference/cli/docker/compose/run/)

View File

@@ -1,47 +0,0 @@
---
title: Develop and Deploy Laravel applications with Docker Compose
linkTitle: Laravel
summary: Learn how to efficiently set up Laravel development and production environments using Docker Compose.
description: A guide on using Docker Compose to manage Laravel applications for development and production, covering container configurations and service management.
keywords: laravel, php, docker compose, web framework, development, production
tags: [frameworks]
languages: [php]
aliases:
- /frameworks/laravel/
params:
time: 30 minutes
resource_links:
- title: Laravel
url: https://laravel.com/
- title: Docker Compose
url: /compose/
- title: Use Compose in production
url: /compose/how-tos/production/
- title: Repository with examples
url: https://github.com/dockersamples/laravel-docker-examples
---
Laravel is a popular PHP framework that allows developers to build web applications quickly and effectively. Docker Compose simplifies the management of development and production environments by defining essential services, like PHP, a web server, and a database, in a single YAML file. This guide provides a streamlined approach to setting up a robust Laravel environment using Docker Compose, focusing on simplicity and efficiency.
> **Acknowledgment**
>
> Docker would like to thank [Sergei Shitikov](https://github.com/rw4lll) for
> his contribution to this guide.
The demonstrated examples can be found in [this GitHub repository](https://github.com/dockersamples/laravel-docker-examples). Docker Compose offers a straightforward approach to connecting multiple containers for Laravel, though similar setups can also be achieved using tools like Docker Swarm, Kubernetes, or individual Docker containers.
This guide is intended for educational purposes, helping developers adapt and optimize configurations for their specific use cases. Additionally, there are existing tools that support Laravel in containers:
- [Laravel Sail](https://laravel.com/docs/12.x/sail): An official package for easily starting Laravel in Docker.
- [Laradock](https://github.com/laradock/laradock): A community project that helps run Laravel applications in Docker.
## What you’ll learn
- How to use Docker Compose to set up a Laravel development and production environment.
- Defining services that make Laravel development easier, including PHP-FPM, Nginx, and database containers.
- Best practices for managing Laravel environments using containerization.
## Who’s this for?
- Developers who work with Laravel and want to streamline environment management.
- DevOps engineers seeking efficient ways to manage and deploy Laravel applications.

View File

@@ -1,38 +0,0 @@
---
title: Common Questions on Using Laravel with Docker
description: Find answers to common questions about setting up and managing Laravel environments with Docker Compose, including troubleshooting and best practices.
keywords: laravel, php, docker compose, faq, troubleshooting, best practices
weight: 40
---
<!-- vale Docker.HeadingLength = NO -->
## 1. Why should I use Docker Compose for Laravel?
Docker Compose is a powerful tool for managing multi-container environments, particularly in development due to its simplicity. With Docker Compose, you can define and connect all necessary services for Laravel, such as PHP, Nginx, and databases, in a single configuration (`compose.*.yaml`). This setup ensures consistency across development, testing, and production environments, streamlining onboarding and reducing discrepancies between local and server setups.
While Docker Compose is a great choice for development, tools like **Docker Swarm** or **Kubernetes** offer advanced scaling and orchestration features, which may be beneficial for complex production deployments.
## 2. How do I debug my Laravel application with Docker Compose?
To debug your Laravel application in a Docker environment, use **Xdebug**. In the development setup, Xdebug is installed in the `php-fpm` container to enable debugging. Ensure Xdebug is enabled in your `compose.dev.yaml` file by setting the environment variable `XDEBUG_ENABLED=true` and configuring your IDE (e.g., Visual Studio Code or PHPStorm) to connect to the remote container for debugging.
## 3. Can I use Docker Compose with databases other than PostgreSQL?
Yes, Docker Compose supports various database services for Laravel. While PostgreSQL is used in the examples, you can easily substitute **MySQL**, **MariaDB**, or even **SQLite**. Update the `compose.*.yaml` file to specify the required Docker image and adjust your `.env` file to reflect the new database configuration.
## 4. How can I persist data in development and production?
In both development and production, Docker volumes are used to persist data. For instance, in the `compose.*.yaml` file, the `postgres-data-*` volume stores PostgreSQL data, ensuring that data is retained even if the container restarts. You can also define named volumes for other services where data persistence is essential.
## 5. What is the difference between development and production Docker configurations?
In a development environment, Docker configurations include tools that streamline coding and debugging, such as Xdebug for debugging, and volume mounts to enable real-time code updates without requiring image rebuilds.
In production, the configuration is optimized for performance, security, and efficiency. This setup uses multi-stage builds to keep the image lightweight and includes only essential tools, packages, and libraries.
It’s recommended to use `alpine`-based images in production for smaller image sizes, enhancing deployment speed and security.
Additionally, consider using [Docker Scout](/manuals/scout/_index.md) to detect and analyze vulnerabilities, especially in production environments.
For additional information about using Docker Compose in production, see [this guide](/compose/how-tos/production/).

View File

@@ -1,328 +0,0 @@
---
title: Laravel Development Setup with Docker Compose
description: Set up a Laravel development environment using Docker Compose.
keywords: laravel, php, docker compose, development, xdebug, php-fpm, nginx
weight: 30
---
This guide demonstrates how to configure a **development** environment for a Laravel application using Docker and Docker Compose. It builds **on top of** the production image for PHP-FPM and then adds developer-focused features—like Xdebug—to streamline debugging. By basing the development container on a known production image, you keep both environments closely aligned.
This setup includes PHP-FPM, Nginx, and PostgreSQL services (although you can easily swap PostgreSQL for another database, like MySQL or MariaDB). Everything runs in containers, so you can develop in isolation without altering your host system.
> [!NOTE]
> To experiment with a ready-to-run configuration, download the [Laravel Docker Examples](https://github.com/dockersamples/laravel-docker-examples) repository. It contains pre-configured setups for both development and production.
## Project structure
```plaintext
my-laravel-app/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── docker/
│ ├── common/
│ │ └── php-fpm/
│ │ └── Dockerfile
│ ├── development/
│ │ ├── php-fpm/
│ │ │ └── entrypoint.sh
│ │ ├── workspace/
│ │ │ └── Dockerfile
│ │ └── nginx
│ │ ├── Dockerfile
│ │ └── nginx.conf
│ └── production/
├── compose.dev.yaml
├── compose.prod.yaml
├── .dockerignore
├── .env
├── vendor/
├── ...
```
This layout represents a typical Laravel project, with Docker configurations stored in a unified `docker` directory. You’ll find **two** Compose files — `compose.dev.yaml` (for development) and `compose.prod.yaml` (for production) — to keep your environments separate and manageable.
The environment includes a `workspace` service, a sidecar container for tasks like building front-end assets, running Artisan commands, and other CLI tools your project may require. While this extra container may seem unusual, it’s a familiar pattern in solutions like **Laravel Sail** and **Laradock**. It also includes **Xdebug** to aid in debugging.
## Create a Dockerfile for PHP-FPM
This Dockerfile **extends** the production image by installing Xdebug and adjusting user permissions to ease local development. That way, your development environment stays consistent with production while still offering extra debug features and improved file mounting.
```dockerfile
# Builds a dev-only layer on top of the production image
FROM production AS development
# Use ARGs to define environment variables passed from the Docker build command or Docker Compose.
ARG XDEBUG_ENABLED=true
ARG XDEBUG_MODE=develop,coverage,debug,profile
ARG XDEBUG_HOST=host.docker.internal
ARG XDEBUG_IDE_KEY=DOCKER
ARG XDEBUG_LOG=/dev/stdout
ARG XDEBUG_LOG_LEVEL=0
USER root
# Configure Xdebug if enabled
RUN if [ "${XDEBUG_ENABLED}" = "true" ]; then \
pecl install xdebug && \
docker-php-ext-enable xdebug && \
echo "xdebug.mode=${XDEBUG_MODE}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.idekey=${XDEBUG_IDE_KEY}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log=${XDEBUG_LOG}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log_level=${XDEBUG_LOG_LEVEL}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.client_host=${XDEBUG_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
fi
# Add ARGs for syncing permissions
ARG UID=1000
ARG GID=1000
# Create a new user with the specified UID and GID, reusing an existing group if GID exists
RUN if getent group ${GID}; then \
group_name=$(getent group ${GID} | cut -d: -f1); \
useradd -m -u ${UID} -g ${GID} -s /bin/bash www; \
else \
groupadd -g ${GID} www && \
useradd -m -u ${UID} -g www -s /bin/bash www; \
group_name=www; \
fi
# Dynamically update php-fpm to use the new user and group
RUN sed -i "s/user = www-data/user = www/g" /usr/local/etc/php-fpm.d/www.conf && \
sed -i "s/group = www-data/group = $group_name/g" /usr/local/etc/php-fpm.d/www.conf
# Set the working directory
WORKDIR /var/www
# Copy the entrypoint script
COPY ./docker/development/php-fpm/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Switch back to the non-privileged user to run the application
USER www-data
# Change the default command to run the entrypoint script
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
```
## Create a Dockerfile for Workspace
A workspace container provides a dedicated shell for asset compilation, Artisan/Composer commands, and other CLI tasks. This approach follows patterns from Laravel Sail and Laradock, consolidating all development tools into one container for convenience.
```dockerfile
# docker/development/workspace/Dockerfile
# Use the official PHP CLI image as the base
FROM php:8.5-cli
# Set environment variables for user and group ID
ARG UID=1000
ARG GID=1000
ARG NODE_VERSION=22.0.0
# Install system dependencies and build libraries
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
intl \
zip \
bcmath \
soap \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Use ARG to define environment variables passed from the Docker build command or Docker Compose.
ARG XDEBUG_ENABLED
ARG XDEBUG_MODE
ARG XDEBUG_HOST
ARG XDEBUG_IDE_KEY
ARG XDEBUG_LOG
ARG XDEBUG_LOG_LEVEL
# Configure Xdebug if enabled
RUN if [ "${XDEBUG_ENABLED}" = "true" ]; then \
pecl install xdebug && \
docker-php-ext-enable xdebug && \
echo "xdebug.mode=${XDEBUG_MODE}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.idekey=${XDEBUG_IDE_KEY}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log=${XDEBUG_LOG}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log_level=${XDEBUG_LOG_LEVEL}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.client_host=${XDEBUG_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
fi
# If the group already exists, use it; otherwise, create the 'www' group
RUN if getent group ${GID}; then \
useradd -m -u ${UID} -g ${GID} -s /bin/bash www; \
else \
groupadd -g ${GID} www && \
useradd -m -u ${UID} -g www -s /bin/bash www; \
fi && \
usermod -aG sudo www && \
echo 'www ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# Switch to the non-root user to install NVM and Node.js
USER www
# Install NVM (Node Version Manager) as the www user
RUN export NVM_DIR="$HOME/.nvm" && \
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash && \
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && \
nvm install ${NODE_VERSION} && \
nvm alias default ${NODE_VERSION} && \
nvm use default
# Ensure NVM is available for all future shells
RUN echo 'export NVM_DIR="$HOME/.nvm"' >> /home/www/.bashrc && \
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> /home/www/.bashrc && \
echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"' >> /home/www/.bashrc
# Set the working directory
WORKDIR /var/www
# Override the entrypoint to avoid the default php entrypoint
ENTRYPOINT []
# Default command to keep the container running
CMD ["bash"]
```
> [!NOTE]
> If you prefer a **one-service-per-container** approach, simply omit the workspace container and run separate containers for each task. For example, you could use a dedicated `php-cli` container for your PHP scripts, and a `node` container to handle the asset building.
## Create a Docker Compose configuration for development
Here's the `compose.yaml` file to set up the development environment:
```yaml
services:
web:
image: nginx:latest # Using the default Nginx image with custom configuration.
volumes:
# Mount the application code for live updates
- ./:/var/www
# Mount the Nginx configuration file
- ./docker/development/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
ports:
# Map port 80 inside the container to the port specified by 'NGINX_PORT' on the host machine
- "80:80"
environment:
- NGINX_HOST=localhost
networks:
- laravel-development
depends_on:
php-fpm:
condition: service_started # Wait for php-fpm to start
php-fpm:
# For the php-fpm service, we will use our common PHP-FPM Dockerfile with the development target
build:
context: .
dockerfile: ./docker/common/php-fpm/Dockerfile
target: development
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
XDEBUG_ENABLED: ${XDEBUG_ENABLED:-true}
XDEBUG_MODE: develop,coverage,debug,profile
XDEBUG_HOST: ${XDEBUG_HOST:-host.docker.internal}
XDEBUG_IDE_KEY: ${XDEBUG_IDE_KEY:-DOCKER}
XDEBUG_LOG: /dev/stdout
XDEBUG_LOG_LEVEL: 0
env_file:
# Load the environment variables from the Laravel application
- .env
user: "${UID:-1000}:${GID:-1000}"
volumes:
# Mount the application code for live updates
- ./:/var/www
networks:
- laravel-development
depends_on:
postgres:
condition: service_started # Wait for postgres to start
workspace:
# For the workspace service, we will also create a custom image to install and setup all the necessary stuff.
build:
context: .
dockerfile: ./docker/development/workspace/Dockerfile
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
XDEBUG_ENABLED: ${XDEBUG_ENABLED:-true}
XDEBUG_MODE: develop,coverage,debug,profile
XDEBUG_HOST: ${XDEBUG_HOST:-host.docker.internal}
XDEBUG_IDE_KEY: ${XDEBUG_IDE_KEY:-DOCKER}
XDEBUG_LOG: /dev/stdout
XDEBUG_LOG_LEVEL: 0
tty: true # Enables an interactive terminal
stdin_open: true # Keeps standard input open for 'docker exec'
env_file:
- .env
volumes:
- ./:/var/www
networks:
- laravel-development
postgres:
image: postgres:18
ports:
- "${POSTGRES_PORT:-5432}:5432"
environment:
- POSTGRES_DB=app
- POSTGRES_USER=laravel
- POSTGRES_PASSWORD=secret
volumes:
- postgres-data-development:/var/lib/postgresql
networks:
- laravel-development
redis:
image: redis:alpine
networks:
- laravel-development
networks:
laravel-development:
volumes:
postgres-data-development:
```
> [!NOTE]
> Ensure you have an `.env` file at the root of your Laravel project with the necessary configurations. You can use the `.env.example` file as a template.
## Run your development environment
To start the development environment, use:
```console
$ docker compose -f compose.dev.yaml up --build -d
```
Run this command to build and start the development environment in detached mode. When the containers finish initializing, visit [http://localhost/](http://localhost/) to see your Laravel app in action.
## Summary
By building on top of the production image and adding debug tools like Xdebug, you create a Laravel development workflow that closely mirrors production. The optional workspace container simplifies tasks like asset building and running Artisan commands. If you prefer a separate container for every service (e.g., a dedicated `php-cli` and `node` container), you can skip the workspace approach. Either way, Docker Compose provides an efficient, consistent way to develop your Laravel project.

View File

@@ -0,0 +1,862 @@
---
title: Develop and Deploy Laravel applications with Docker Compose
linkTitle: Laravel
summary: Learn how to efficiently set up Laravel development and production environments using Docker Compose.
description: A guide on using Docker Compose to manage Laravel applications for development and production, covering container configurations and service management.
keywords: laravel, php, docker compose, web framework, development, production
aliases:
- /frameworks/laravel/
- /guides/frameworks/laravel/common-questions/
- /guides/frameworks/laravel/development-setup/
- /guides/frameworks/laravel/prerequisites/
- /guides/frameworks/laravel/production-setup/
params:
tags: [languages]
time: 30 minutes
---
Laravel is a popular PHP framework that allows developers to build web applications quickly and effectively. Docker Compose simplifies the management of development and production environments by defining essential services, like PHP, a web server, and a database, in a single YAML file. This guide provides a streamlined approach to setting up a robust Laravel environment using Docker Compose, focusing on simplicity and efficiency.
> **Acknowledgment**
>
> Docker would like to thank [Sergei Shitikov](https://github.com/rw4lll) for
> his contribution to this guide.
The demonstrated examples can be found in [this GitHub repository](https://github.com/dockersamples/laravel-docker-examples). Docker Compose offers a straightforward approach to connecting multiple containers for Laravel, though similar setups can also be achieved using tools like Docker Swarm, Kubernetes, or individual Docker containers.
This guide is intended for educational purposes, helping developers adapt and optimize configurations for their specific use cases. Additionally, there are existing tools that support Laravel in containers:
- [Laravel Sail](https://laravel.com/docs/12.x/sail): An official package for easily starting Laravel in Docker.
- [Laradock](https://github.com/laradock/laradock): A community project that helps run Laravel applications in Docker.
## What you’ll learn
- How to use Docker Compose to set up a Laravel development and production environment.
- Defining services that make Laravel development easier, including PHP-FPM, Nginx, and database containers.
- Best practices for managing Laravel environments using containerization.
## Who’s this for?
- Developers who work with Laravel and want to streamline environment management.
- DevOps engineers seeking efficient ways to manage and deploy Laravel applications.
## Prerequisites for Setting Up Laravel with Docker Compose
Before you begin setting up Laravel with Docker Compose, make sure you meet the following prerequisites:
### Docker and Docker Compose
You need Docker and Docker Compose installed on your system. Docker allows you to containerize applications, and Docker Compose helps you manage multi-container applications.
- Docker: Make sure Docker is installed and running on your machine. Refer to the [Docker installation guide](/get-docker/) to install Docker.
- Docker Compose: Docker Compose is included with Docker Desktop, but you can also follow the [Docker Compose installation guide](/compose/install/) if needed.
### Basic understanding of Docker and containers
A fundamental understanding of Docker and how containers work will be helpful. If you're new to Docker, consider reviewing the [Docker Overview](/get-started/overview/) to familiarize yourself with containerization concepts.
### Basic knowledge of Laravel
This guide assumes you have a basic understanding of Laravel and PHP. Familiarity with Laravel’s command-line tools, such as [Artisan](https://laravel.com/docs/12.x/artisan), and its project structure is important for following the instructions.
- Laravel CLI: You should be comfortable using Laravel’s command-line tool (`artisan`).
- Laravel Project Structure: Familiarize yourself with Laravel’s folder structure (`app`, `config`, `routes`, `tests`, etc.).
## Laravel Production Setup with Docker Compose
This guide demonstrates how to set up a production-ready Laravel environment using Docker and Docker Compose. This configuration is designed for streamlined, scalable, and secure Laravel application deployments.
> [!NOTE]
> To experiment with a ready-to-run configuration, download the [Laravel Docker Examples](https://github.com/dockersamples/laravel-docker-examples) repository. It contains pre-configured setups for both development and production.
### Project structure
```plaintext
my-laravel-app/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── docker/
│ ├── common/
│ │ └── php-fpm/
│ │ ├── Dockerfile
│ │ └── conf.d/
│ │ └── 20-status-path.conf
│ ├── development/
│ ├── production/
│ │ ├── php-fpm/
│ │ │ └── entrypoint.sh
│ │ └── nginx
│ │ ├── Dockerfile
│ │ └── nginx.conf
├── compose.dev.yaml
├── compose.prod.yaml
├── .dockerignore
├── .env
├── vendor/
├── ...
```
This layout represents a typical Laravel project, with Docker configurations stored in a unified `docker` directory. You’ll find **two** Compose files — `compose.dev.yaml` (for development) and `compose.prod.yaml` (for production) — to keep your environments separate and manageable.
### Create a Dockerfile for PHP-FPM (production)
For production, the `php-fpm` Dockerfile creates an optimized image with only the PHP extensions and libraries your application needs. As demonstrated in the [GitHub example](https://github.com/dockersamples/laravel-docker-examples), a single Dockerfile with multi-stage builds maintains consistency and reduces duplication between development and production. The following snippet shows only the production-related stages:
```dockerfile
# Stage 1: Build environment and Composer dependencies
FROM php:8.5-fpm AS builder
# Install system dependencies and PHP extensions for Laravel with MySQL/PostgreSQL support.
# Dependencies in this stage are only required for building the final image.
# Node.js and asset building are handled in the Nginx stage, not here.
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
intl \
zip \
bcmath \
soap \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set the working directory inside the container
WORKDIR /var/www
# Copy the entire Laravel application code into the container
# -----------------------------------------------------------
# In Laravel, `composer install` may trigger scripts
# needing access to application code.
# For example, the `post-autoload-dump` event might execute
# Artisan commands like `php artisan package:discover`. If the
# application code (including the `artisan` file) is not
# present, these commands will fail, leading to build errors.
#
# By copying the entire application code before running
# `composer install`, we ensure that all necessary files are
# available, allowing these scripts to run successfully.
# In other cases, it would be possible to copy composer files
# first, to leverage Docker's layer caching mechanism.
# -----------------------------------------------------------
COPY . /var/www
# Install Composer and dependencies
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& composer install --no-dev --optimize-autoloader --no-interaction --no-progress --prefer-dist
# Stage 2: Production environment
FROM php:8.5-fpm AS production
# Install only runtime libraries needed in production
# libfcgi-bin and procps are required for the php-fpm-healthcheck script
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
libicu-dev \
libzip-dev \
libfcgi-bin \
procps \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Download and install php-fpm health check script
RUN curl -o /usr/local/bin/php-fpm-healthcheck \
https://raw.githubusercontent.com/renatomefi/php-fpm-healthcheck/master/php-fpm-healthcheck \
&& chmod +x /usr/local/bin/php-fpm-healthcheck
# Copy the initialization script
COPY ./docker/php-fpm/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Copy the initial storage structure
COPY ./storage /var/www/storage-init
# Copy PHP extensions and libraries from the builder stage
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/local/bin/docker-php-ext-* /usr/local/bin/
# Use the recommended production PHP configuration
# -----------------------------------------------------------
# PHP provides development and production configurations.
# Here, we replace the default php.ini with the production
# version to apply settings optimized for performance and
# security in a live environment.
# -----------------------------------------------------------
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Keep the image-provided FPM global config intact and add pool overrides separately
COPY ./docker/common/php-fpm/conf.d/*.conf /usr/local/etc/php-fpm.d/
# Update the variables_order to include E (for ENV)
#RUN sed -i 's/variables_order = "GPCS"/variables_order = "EGPCS"/' "$PHP_INI_DIR/php.ini"
# Copy the application code and dependencies from the build stage
COPY --from=builder /var/www /var/www
# Set working directory
WORKDIR /var/www
# Ensure correct permissions
RUN chown -R www-data:www-data /var/www
# Switch to the non-privileged user to run the application
USER www-data
# Change the default command to run the entrypoint script
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
```
### Create a Dockerfile for PHP-CLI (production)
For production, you often need a separate container to run Artisan commands, migrations, and other CLI tasks. In most cases you can run these commands by reusing existing PHP-FPM container:
```console
$ docker compose -f compose.prod.yaml exec php-fpm php artisan route:list
```
If you need a separate CLI container with different extensions or strict separation of concerns, consider a php-cli Dockerfile:
```dockerfile
# Stage 1: Build environment and Composer dependencies
FROM php:8.5-cli AS builder
# Install system dependencies and PHP extensions required for Laravel + MySQL/PostgreSQL support
# Some dependencies are required for PHP extensions only in the build stage
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
intl \
zip \
bcmath \
soap \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set the working directory inside the container
WORKDIR /var/www
# Copy the entire Laravel application code into the container
COPY . /var/www
# Install Composer and dependencies
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& composer install --no-dev --optimize-autoloader --no-interaction --no-progress --prefer-dist
# Stage 2: Production environment
FROM php:8.5-cli
# Install client libraries required for php extensions in runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
libicu-dev \
libzip-dev \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Copy PHP extensions and libraries from the builder stage
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/local/bin/docker-php-ext-* /usr/local/bin/
# Use the default production configuration for PHP runtime arguments
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Copy the application code and dependencies from the build stage
COPY --from=builder /var/www /var/www
# Set working directory
WORKDIR /var/www
# Ensure correct permissions
RUN chown -R www-data:www-data /var/www
# Switch to the non-privileged user to run the application
USER www-data
# Default command: Provide a bash shell to allow running any command
CMD ["bash"]
```
This Dockerfile is similar to the PHP-FPM Dockerfile, but it uses the `php:8.5-cli` image as the base image and sets up the container for running CLI commands.
### Create a Dockerfile for Nginx (production)
Nginx serves as the web server for the Laravel application. You can include static assets directly to the container. Here's an example of possible Dockerfile for Nginx:
```dockerfile
# docker/nginx/Dockerfile
# Stage 1: Build assets
FROM debian AS builder
# Install Node.js and build tools
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
nodejs \
npm \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set working directory
WORKDIR /var/www
# Copy Laravel application code
COPY . /var/www
# Install Node.js dependencies and build assets
RUN npm install && npm run build
# Stage 2: Nginx production image
FROM nginx:alpine
# Copy custom Nginx configuration
# -----------------------------------------------------------
# Replace the default Nginx configuration with our custom one
# that is optimized for serving a Laravel application.
# -----------------------------------------------------------
COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf
# Copy Laravel's public assets from the builder stage
# -----------------------------------------------------------
# We only need the 'public' directory from our Laravel app.
# -----------------------------------------------------------
COPY --from=builder /var/www/public /var/www/public
# Set the working directory to the public folder
WORKDIR /var/www/public
# Expose port 80 and start Nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
This Dockerfile uses a multi-stage build to separate the asset building process from the final production image. The first stage installs Node.js and builds the assets, while the second stage sets up the Nginx production image with the optimized configuration and the built assets.
### Create a Docker Compose configuration for production
To bring all the services together, create a `compose.prod.yaml` file that defines the services, volumes, and networks for the production environment. Here's an example configuration:
```yaml
services:
web:
build:
context: .
dockerfile: ./docker/production/nginx/Dockerfile
restart: unless-stopped # Automatically restart unless the service is explicitly stopped
volumes:
# Mount the 'laravel-storage' volume to '/var/www/storage' inside the container.
# -----------------------------------------------------------
# This volume stores persistent data like uploaded files and cache.
# The ':ro' option mounts it as read-only in the 'web' service because Nginx only needs to read these files.
# The 'php-fpm' service mounts the same volume without ':ro' to allow write operations.
# -----------------------------------------------------------
- laravel-storage-production:/var/www/storage:ro
networks:
- laravel-production
ports:
# Map port 80 inside the container to the port specified by 'NGINX_PORT' on the host machine.
# -----------------------------------------------------------
# This allows external access to the Nginx web server running inside the container.
# For example, if 'NGINX_PORT' is set to '8080', accessing 'http://localhost:8080' will reach the application.
# -----------------------------------------------------------
- "${NGINX_PORT:-80}:80"
depends_on:
php-fpm:
condition: service_healthy # Wait for php-fpm health check
php-fpm:
# For the php-fpm service, we will create a custom image to install the necessary PHP extensions and setup proper permissions.
build:
context: .
dockerfile: ./docker/common/php-fpm/Dockerfile
target: production # Use the 'production' stage in the Dockerfile
restart: unless-stopped
volumes:
- laravel-storage-production:/var/www/storage # Mount the storage volume
env_file:
- .env
networks:
- laravel-production
healthcheck:
test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"]
interval: 10s
timeout: 5s
retries: 3
# The 'depends_on' attribute with 'condition: service_healthy' ensures that
# this service will not start until the 'postgres' service passes its health check.
# This prevents the application from trying to connect to the database before it's ready.
depends_on:
postgres:
condition: service_healthy
# The 'php-cli' service provides a command-line interface for running Artisan commands and other CLI tasks.
# -----------------------------------------------------------
# This is useful for running migrations, seeders, or any custom scripts.
# It shares the same codebase and environment as the 'php-fpm' service.
# -----------------------------------------------------------
php-cli:
build:
context: .
dockerfile: ./docker/php-cli/Dockerfile
tty: true # Enables an interactive terminal
stdin_open: true # Keeps standard input open for 'docker exec'
env_file:
- .env
networks:
- laravel-production
postgres:
image: postgres:18
restart: unless-stopped
user: postgres
ports:
- "${POSTGRES_PORT}:5432"
environment:
- POSTGRES_DB=${POSTGRES_DATABASE}
- POSTGRES_USER=${POSTGRES_USERNAME}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres-data-production:/var/lib/postgresql
networks:
- laravel-production
# Health check for PostgreSQL
# -----------------------------------------------------------
# Health checks allow Docker to determine if a service is operational.
# The 'pg_isready' command checks if PostgreSQL is ready to accept connections.
# This prevents dependent services from starting before the database is ready.
# -----------------------------------------------------------
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:alpine
restart: unless-stopped # Automatically restart unless the service is explicitly stopped
networks:
- laravel-production
# Health check for Redis
# -----------------------------------------------------------
# Checks if Redis is responding to the 'PING' command.
# This ensures that the service is not only running but also operational.
# -----------------------------------------------------------
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
# Attach the service to the 'laravel-production' network.
# -----------------------------------------------------------
# This custom network allows all services within it to communicate using their service names as hostnames.
# For example, 'php-fpm' can connect to 'postgres' by using 'postgres' as the hostname.
# -----------------------------------------------------------
laravel-production:
volumes:
postgres-data-production:
laravel-storage-production:
```
> [!NOTE]
> Ensure you have an `.env` file at the root of your Laravel project with the necessary configurations to match the Docker Compose setup.
### Running your production environment
To start the production environment, run:
```console
$ docker compose -f compose.prod.yaml up --build -d
```
This command will build and start all the services in detached mode, providing a scalable and production-ready setup for your Laravel application.
### Summary
By setting up a Docker Compose environment for Laravel in production, you ensure that your application is optimized for performance, scalable, and secure. This setup makes deployments consistent and easier to manage, reducing the likelihood of errors due to differences between environments.
## Laravel Development Setup with Docker Compose
This guide demonstrates how to configure a **development** environment for a Laravel application using Docker and Docker Compose. It builds **on top of** the production image for PHP-FPM and then adds developer-focused features—like Xdebug—to streamline debugging. By basing the development container on a known production image, you keep both environments closely aligned.
This setup includes PHP-FPM, Nginx, and PostgreSQL services (although you can easily swap PostgreSQL for another database, like MySQL or MariaDB). Everything runs in containers, so you can develop in isolation without altering your host system.
> [!NOTE]
> To experiment with a ready-to-run configuration, download the [Laravel Docker Examples](https://github.com/dockersamples/laravel-docker-examples) repository. It contains pre-configured setups for both development and production.
### Project structure
```plaintext
my-laravel-app/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── docker/
│ ├── common/
│ │ └── php-fpm/
│ │ └── Dockerfile
│ ├── development/
│ │ ├── php-fpm/
│ │ │ └── entrypoint.sh
│ │ ├── workspace/
│ │ │ └── Dockerfile
│ │ └── nginx
│ │ ├── Dockerfile
│ │ └── nginx.conf
│ └── production/
├── compose.dev.yaml
├── compose.prod.yaml
├── .dockerignore
├── .env
├── vendor/
├── ...
```
This layout represents a typical Laravel project, with Docker configurations stored in a unified `docker` directory. You’ll find **two** Compose files — `compose.dev.yaml` (for development) and `compose.prod.yaml` (for production) — to keep your environments separate and manageable.
The environment includes a `workspace` service, a sidecar container for tasks like building front-end assets, running Artisan commands, and other CLI tools your project may require. While this extra container may seem unusual, it’s a familiar pattern in solutions like **Laravel Sail** and **Laradock**. It also includes **Xdebug** to aid in debugging.
### Create a Dockerfile for PHP-FPM
This Dockerfile **extends** the production image by installing Xdebug and adjusting user permissions to ease local development. That way, your development environment stays consistent with production while still offering extra debug features and improved file mounting.
```dockerfile
# Builds a dev-only layer on top of the production image
FROM production AS development
# Use ARGs to define environment variables passed from the Docker build command or Docker Compose.
ARG XDEBUG_ENABLED=true
ARG XDEBUG_MODE=develop,coverage,debug,profile
ARG XDEBUG_HOST=host.docker.internal
ARG XDEBUG_IDE_KEY=DOCKER
ARG XDEBUG_LOG=/dev/stdout
ARG XDEBUG_LOG_LEVEL=0
USER root
# Configure Xdebug if enabled
RUN if [ "${XDEBUG_ENABLED}" = "true" ]; then \
pecl install xdebug && \
docker-php-ext-enable xdebug && \
echo "xdebug.mode=${XDEBUG_MODE}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.idekey=${XDEBUG_IDE_KEY}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log=${XDEBUG_LOG}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log_level=${XDEBUG_LOG_LEVEL}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.client_host=${XDEBUG_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
fi
# Add ARGs for syncing permissions
ARG UID=1000
ARG GID=1000
# Create a new user with the specified UID and GID, reusing an existing group if GID exists
RUN if getent group ${GID}; then \
group_name=$(getent group ${GID} | cut -d: -f1); \
useradd -m -u ${UID} -g ${GID} -s /bin/bash www; \
else \
groupadd -g ${GID} www && \
useradd -m -u ${UID} -g www -s /bin/bash www; \
group_name=www; \
fi
# Dynamically update php-fpm to use the new user and group
RUN sed -i "s/user = www-data/user = www/g" /usr/local/etc/php-fpm.d/www.conf && \
sed -i "s/group = www-data/group = $group_name/g" /usr/local/etc/php-fpm.d/www.conf
# Set the working directory
WORKDIR /var/www
# Copy the entrypoint script
COPY ./docker/development/php-fpm/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Switch back to the non-privileged user to run the application
USER www-data
# Change the default command to run the entrypoint script
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
```
### Create a Dockerfile for Workspace
A workspace container provides a dedicated shell for asset compilation, Artisan/Composer commands, and other CLI tasks. This approach follows patterns from Laravel Sail and Laradock, consolidating all development tools into one container for convenience.
```dockerfile
# docker/development/workspace/Dockerfile
# Use the official PHP CLI image as the base
FROM php:8.5-cli
# Set environment variables for user and group ID
ARG UID=1000
ARG GID=1000
ARG NODE_VERSION=22.0.0
# Install system dependencies and build libraries
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
intl \
zip \
bcmath \
soap \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Use ARG to define environment variables passed from the Docker build command or Docker Compose.
ARG XDEBUG_ENABLED
ARG XDEBUG_MODE
ARG XDEBUG_HOST
ARG XDEBUG_IDE_KEY
ARG XDEBUG_LOG
ARG XDEBUG_LOG_LEVEL
# Configure Xdebug if enabled
RUN if [ "${XDEBUG_ENABLED}" = "true" ]; then \
pecl install xdebug && \
docker-php-ext-enable xdebug && \
echo "xdebug.mode=${XDEBUG_MODE}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.idekey=${XDEBUG_IDE_KEY}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log=${XDEBUG_LOG}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.log_level=${XDEBUG_LOG_LEVEL}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && \
echo "xdebug.client_host=${XDEBUG_HOST}" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini ; \
fi
# If the group already exists, use it; otherwise, create the 'www' group
RUN if getent group ${GID}; then \
useradd -m -u ${UID} -g ${GID} -s /bin/bash www; \
else \
groupadd -g ${GID} www && \
useradd -m -u ${UID} -g www -s /bin/bash www; \
fi && \
usermod -aG sudo www && \
echo 'www ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# Switch to the non-root user to install NVM and Node.js
USER www
# Install NVM (Node Version Manager) as the www user
RUN export NVM_DIR="$HOME/.nvm" && \
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash && \
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && \
nvm install ${NODE_VERSION} && \
nvm alias default ${NODE_VERSION} && \
nvm use default
# Ensure NVM is available for all future shells
RUN echo 'export NVM_DIR="$HOME/.nvm"' >> /home/www/.bashrc && \
echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> /home/www/.bashrc && \
echo '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"' >> /home/www/.bashrc
# Set the working directory
WORKDIR /var/www
# Override the entrypoint to avoid the default php entrypoint
ENTRYPOINT []
# Default command to keep the container running
CMD ["bash"]
```
> [!NOTE]
> If you prefer a **one-service-per-container** approach, simply omit the workspace container and run separate containers for each task. For example, you could use a dedicated `php-cli` container for your PHP scripts, and a `node` container to handle the asset building.
### Create a Docker Compose configuration for development
Here's the `compose.yaml` file to set up the development environment:
```yaml
services:
web:
image: nginx:latest # Using the default Nginx image with custom configuration.
volumes:
# Mount the application code for live updates
- ./:/var/www
# Mount the Nginx configuration file
- ./docker/development/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
ports:
# Map port 80 inside the container to the port specified by 'NGINX_PORT' on the host machine
- "80:80"
environment:
- NGINX_HOST=localhost
networks:
- laravel-development
depends_on:
php-fpm:
condition: service_started # Wait for php-fpm to start
php-fpm:
# For the php-fpm service, we will use our common PHP-FPM Dockerfile with the development target
build:
context: .
dockerfile: ./docker/common/php-fpm/Dockerfile
target: development
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
XDEBUG_ENABLED: ${XDEBUG_ENABLED:-true}
XDEBUG_MODE: develop,coverage,debug,profile
XDEBUG_HOST: ${XDEBUG_HOST:-host.docker.internal}
XDEBUG_IDE_KEY: ${XDEBUG_IDE_KEY:-DOCKER}
XDEBUG_LOG: /dev/stdout
XDEBUG_LOG_LEVEL: 0
env_file:
# Load the environment variables from the Laravel application
- .env
user: "${UID:-1000}:${GID:-1000}"
volumes:
# Mount the application code for live updates
- ./:/var/www
networks:
- laravel-development
depends_on:
postgres:
condition: service_started # Wait for postgres to start
workspace:
# For the workspace service, we will also create a custom image to install and setup all the necessary stuff.
build:
context: .
dockerfile: ./docker/development/workspace/Dockerfile
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
XDEBUG_ENABLED: ${XDEBUG_ENABLED:-true}
XDEBUG_MODE: develop,coverage,debug,profile
XDEBUG_HOST: ${XDEBUG_HOST:-host.docker.internal}
XDEBUG_IDE_KEY: ${XDEBUG_IDE_KEY:-DOCKER}
XDEBUG_LOG: /dev/stdout
XDEBUG_LOG_LEVEL: 0
tty: true # Enables an interactive terminal
stdin_open: true # Keeps standard input open for 'docker exec'
env_file:
- .env
volumes:
- ./:/var/www
networks:
- laravel-development
postgres:
image: postgres:18
ports:
- "${POSTGRES_PORT:-5432}:5432"
environment:
- POSTGRES_DB=app
- POSTGRES_USER=laravel
- POSTGRES_PASSWORD=secret
volumes:
- postgres-data-development:/var/lib/postgresql
networks:
- laravel-development
redis:
image: redis:alpine
networks:
- laravel-development
networks:
laravel-development:
volumes:
postgres-data-development:
```
> [!NOTE]
> Ensure you have an `.env` file at the root of your Laravel project with the necessary configurations. You can use the `.env.example` file as a template.
### Run your development environment
To start the development environment, use:
```console
$ docker compose -f compose.dev.yaml up --build -d
```
Run this command to build and start the development environment in detached mode. When the containers finish initializing, visit [http://localhost/](http://localhost/) to see your Laravel app in action.
### Summary
By building on top of the production image and adding debug tools like Xdebug, you create a Laravel development workflow that closely mirrors production. The optional workspace container simplifies tasks like asset building and running Artisan commands. If you prefer a separate container for every service (e.g., a dedicated `php-cli` and `node` container), you can skip the workspace approach. Either way, Docker Compose provides an efficient, consistent way to develop your Laravel project.
## Common Questions on Using Laravel with Docker
<!-- vale Docker.HeadingLength = NO -->
### 1. Why should I use Docker Compose for Laravel?
Docker Compose is a powerful tool for managing multi-container environments, particularly in development due to its simplicity. With Docker Compose, you can define and connect all necessary services for Laravel, such as PHP, Nginx, and databases, in a single configuration (`compose.*.yaml`). This setup ensures consistency across development, testing, and production environments, streamlining onboarding and reducing discrepancies between local and server setups.
While Docker Compose is a great choice for development, tools like **Docker Swarm** or **Kubernetes** offer advanced scaling and orchestration features, which may be beneficial for complex production deployments.
### 2. How do I debug my Laravel application with Docker Compose?
To debug your Laravel application in a Docker environment, use **Xdebug**. In the development setup, Xdebug is installed in the `php-fpm` container to enable debugging. Ensure Xdebug is enabled in your `compose.dev.yaml` file by setting the environment variable `XDEBUG_ENABLED=true` and configuring your IDE (e.g., Visual Studio Code or PHPStorm) to connect to the remote container for debugging.
### 3. Can I use Docker Compose with databases other than PostgreSQL?
Yes, Docker Compose supports various database services for Laravel. While PostgreSQL is used in the examples, you can easily substitute **MySQL**, **MariaDB**, or even **SQLite**. Update the `compose.*.yaml` file to specify the required Docker image and adjust your `.env` file to reflect the new database configuration.
### 4. How can I persist data in development and production?
In both development and production, Docker volumes are used to persist data. For instance, in the `compose.*.yaml` file, the `postgres-data-*` volume stores PostgreSQL data, ensuring that data is retained even if the container restarts. You can also define named volumes for other services where data persistence is essential.
### 5. What is the difference between development and production Docker configurations?
In a development environment, Docker configurations include tools that streamline coding and debugging, such as Xdebug for debugging, and volume mounts to enable real-time code updates without requiring image rebuilds.
In production, the configuration is optimized for performance, security, and efficiency. This setup uses multi-stage builds to keep the image lightweight and includes only essential tools, packages, and libraries.
It’s recommended to use `alpine`-based images in production for smaller image sizes, enhancing deployment speed and security.
Additionally, consider using [Docker Scout](/manuals/scout/_index.md) to detect and analyze vulnerabilities, especially in production environments.
For additional information about using Docker Compose in production, see [this guide](/compose/how-tos/production/).

View File

@@ -1,26 +0,0 @@
---
title: Prerequisites for Setting Up Laravel with Docker Compose
description: Ensure you have the required tools and knowledge before setting up Laravel with Docker Compose.
keywords: laravel, php, docker compose, prerequisites, requirements, setup
weight: 10
---
Before you begin setting up Laravel with Docker Compose, make sure you meet the following prerequisites:
## Docker and Docker Compose
You need Docker and Docker Compose installed on your system. Docker allows you to containerize applications, and Docker Compose helps you manage multi-container applications.
- Docker: Make sure Docker is installed and running on your machine. Refer to the [Docker installation guide](/get-docker/) to install Docker.
- Docker Compose: Docker Compose is included with Docker Desktop, but you can also follow the [Docker Compose installation guide](/compose/install/) if needed.
## Basic understanding of Docker and containers
A fundamental understanding of Docker and how containers work will be helpful. If you're new to Docker, consider reviewing the [Docker Overview](/get-started/overview/) to familiarize yourself with containerization concepts.
## Basic knowledge of Laravel
This guide assumes you have a basic understanding of Laravel and PHP. Familiarity with Laravel’s command-line tools, such as [Artisan](https://laravel.com/docs/12.x/artisan), and its project structure is important for following the instructions.
- Laravel CLI: You should be comfortable using Laravel’s command-line tool (`artisan`).
- Laravel Project Structure: Familiarize yourself with Laravel’s folder structure (`app`, `config`, `routes`, `tests`, etc.).

View File

@@ -1,444 +0,0 @@
---
title: Laravel Production Setup with Docker Compose
description: Set up a production-ready environment for Laravel using Docker Compose.
keywords: laravel, php, docker compose, production, deployment, php-fpm
weight: 20
---
This guide demonstrates how to set up a production-ready Laravel environment using Docker and Docker Compose. This configuration is designed for streamlined, scalable, and secure Laravel application deployments.
> [!NOTE]
> To experiment with a ready-to-run configuration, download the [Laravel Docker Examples](https://github.com/dockersamples/laravel-docker-examples) repository. It contains pre-configured setups for both development and production.
## Project structure
```plaintext
my-laravel-app/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
├── docker/
│ ├── common/
│ │ └── php-fpm/
│ │ ├── Dockerfile
│ │ └── conf.d/
│ │ └── 20-status-path.conf
│ ├── development/
│ ├── production/
│ │ ├── php-fpm/
│ │ │ └── entrypoint.sh
│ │ └── nginx
│ │ ├── Dockerfile
│ │ └── nginx.conf
├── compose.dev.yaml
├── compose.prod.yaml
├── .dockerignore
├── .env
├── vendor/
├── ...
```
This layout represents a typical Laravel project, with Docker configurations stored in a unified `docker` directory. You’ll find **two** Compose files — `compose.dev.yaml` (for development) and `compose.prod.yaml` (for production) — to keep your environments separate and manageable.
## Create a Dockerfile for PHP-FPM (production)
For production, the `php-fpm` Dockerfile creates an optimized image with only the PHP extensions and libraries your application needs. As demonstrated in the [GitHub example](https://github.com/dockersamples/laravel-docker-examples), a single Dockerfile with multi-stage builds maintains consistency and reduces duplication between development and production. The following snippet shows only the production-related stages:
```dockerfile
# Stage 1: Build environment and Composer dependencies
FROM php:8.5-fpm AS builder
# Install system dependencies and PHP extensions for Laravel with MySQL/PostgreSQL support.
# Dependencies in this stage are only required for building the final image.
# Node.js and asset building are handled in the Nginx stage, not here.
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
intl \
zip \
bcmath \
soap \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set the working directory inside the container
WORKDIR /var/www
# Copy the entire Laravel application code into the container
# -----------------------------------------------------------
# In Laravel, `composer install` may trigger scripts
# needing access to application code.
# For example, the `post-autoload-dump` event might execute
# Artisan commands like `php artisan package:discover`. If the
# application code (including the `artisan` file) is not
# present, these commands will fail, leading to build errors.
#
# By copying the entire application code before running
# `composer install`, we ensure that all necessary files are
# available, allowing these scripts to run successfully.
# In other cases, it would be possible to copy composer files
# first, to leverage Docker's layer caching mechanism.
# -----------------------------------------------------------
COPY . /var/www
# Install Composer and dependencies
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& composer install --no-dev --optimize-autoloader --no-interaction --no-progress --prefer-dist
# Stage 2: Production environment
FROM php:8.5-fpm AS production
# Install only runtime libraries needed in production
# libfcgi-bin and procps are required for the php-fpm-healthcheck script
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
libicu-dev \
libzip-dev \
libfcgi-bin \
procps \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Download and install php-fpm health check script
RUN curl -o /usr/local/bin/php-fpm-healthcheck \
https://raw.githubusercontent.com/renatomefi/php-fpm-healthcheck/master/php-fpm-healthcheck \
&& chmod +x /usr/local/bin/php-fpm-healthcheck
# Copy the initialization script
COPY ./docker/php-fpm/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Copy the initial storage structure
COPY ./storage /var/www/storage-init
# Copy PHP extensions and libraries from the builder stage
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/local/bin/docker-php-ext-* /usr/local/bin/
# Use the recommended production PHP configuration
# -----------------------------------------------------------
# PHP provides development and production configurations.
# Here, we replace the default php.ini with the production
# version to apply settings optimized for performance and
# security in a live environment.
# -----------------------------------------------------------
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Keep the image-provided FPM global config intact and add pool overrides separately
COPY ./docker/common/php-fpm/conf.d/*.conf /usr/local/etc/php-fpm.d/
# Update the variables_order to include E (for ENV)
#RUN sed -i 's/variables_order = "GPCS"/variables_order = "EGPCS"/' "$PHP_INI_DIR/php.ini"
# Copy the application code and dependencies from the build stage
COPY --from=builder /var/www /var/www
# Set working directory
WORKDIR /var/www
# Ensure correct permissions
RUN chown -R www-data:www-data /var/www
# Switch to the non-privileged user to run the application
USER www-data
# Change the default command to run the entrypoint script
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]
```
## Create a Dockerfile for PHP-CLI (production)
For production, you often need a separate container to run Artisan commands, migrations, and other CLI tasks. In most cases you can run these commands by reusing existing PHP-FPM container:
```console
$ docker compose -f compose.prod.yaml exec php-fpm php artisan route:list
```
If you need a separate CLI container with different extensions or strict separation of concerns, consider a php-cli Dockerfile:
```dockerfile
# Stage 1: Build environment and Composer dependencies
FROM php:8.5-cli AS builder
# Install system dependencies and PHP extensions required for Laravel + MySQL/PostgreSQL support
# Some dependencies are required for PHP extensions only in the build stage
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
intl \
zip \
bcmath \
soap \
&& pecl install redis \
&& docker-php-ext-enable redis \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set the working directory inside the container
WORKDIR /var/www
# Copy the entire Laravel application code into the container
COPY . /var/www
# Install Composer and dependencies
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& composer install --no-dev --optimize-autoloader --no-interaction --no-progress --prefer-dist
# Stage 2: Production environment
FROM php:8.5-cli
# Install client libraries required for php extensions in runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
libicu-dev \
libzip-dev \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Copy PHP extensions and libraries from the builder stage
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/local/bin/docker-php-ext-* /usr/local/bin/
# Use the default production configuration for PHP runtime arguments
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# Copy the application code and dependencies from the build stage
COPY --from=builder /var/www /var/www
# Set working directory
WORKDIR /var/www
# Ensure correct permissions
RUN chown -R www-data:www-data /var/www
# Switch to the non-privileged user to run the application
USER www-data
# Default command: Provide a bash shell to allow running any command
CMD ["bash"]
```
This Dockerfile is similar to the PHP-FPM Dockerfile, but it uses the `php:8.5-cli` image as the base image and sets up the container for running CLI commands.
## Create a Dockerfile for Nginx (production)
Nginx serves as the web server for the Laravel application. You can include static assets directly to the container. Here's an example of possible Dockerfile for Nginx:
```dockerfile
# docker/nginx/Dockerfile
# Stage 1: Build assets
FROM debian AS builder
# Install Node.js and build tools
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
nodejs \
npm \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set working directory
WORKDIR /var/www
# Copy Laravel application code
COPY . /var/www
# Install Node.js dependencies and build assets
RUN npm install && npm run build
# Stage 2: Nginx production image
FROM nginx:alpine
# Copy custom Nginx configuration
# -----------------------------------------------------------
# Replace the default Nginx configuration with our custom one
# that is optimized for serving a Laravel application.
# -----------------------------------------------------------
COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf
# Copy Laravel's public assets from the builder stage
# -----------------------------------------------------------
# We only need the 'public' directory from our Laravel app.
# -----------------------------------------------------------
COPY --from=builder /var/www/public /var/www/public
# Set the working directory to the public folder
WORKDIR /var/www/public
# Expose port 80 and start Nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
This Dockerfile uses a multi-stage build to separate the asset building process from the final production image. The first stage installs Node.js and builds the assets, while the second stage sets up the Nginx production image with the optimized configuration and the built assets.
## Create a Docker Compose configuration for production
To bring all the services together, create a `compose.prod.yaml` file that defines the services, volumes, and networks for the production environment. Here's an example configuration:
```yaml
services:
web:
build:
context: .
dockerfile: ./docker/production/nginx/Dockerfile
restart: unless-stopped # Automatically restart unless the service is explicitly stopped
volumes:
# Mount the 'laravel-storage' volume to '/var/www/storage' inside the container.
# -----------------------------------------------------------
# This volume stores persistent data like uploaded files and cache.
# The ':ro' option mounts it as read-only in the 'web' service because Nginx only needs to read these files.
# The 'php-fpm' service mounts the same volume without ':ro' to allow write operations.
# -----------------------------------------------------------
- laravel-storage-production:/var/www/storage:ro
networks:
- laravel-production
ports:
# Map port 80 inside the container to the port specified by 'NGINX_PORT' on the host machine.
# -----------------------------------------------------------
# This allows external access to the Nginx web server running inside the container.
# For example, if 'NGINX_PORT' is set to '8080', accessing 'http://localhost:8080' will reach the application.
# -----------------------------------------------------------
- "${NGINX_PORT:-80}:80"
depends_on:
php-fpm:
condition: service_healthy # Wait for php-fpm health check
php-fpm:
# For the php-fpm service, we will create a custom image to install the necessary PHP extensions and setup proper permissions.
build:
context: .
dockerfile: ./docker/common/php-fpm/Dockerfile
target: production # Use the 'production' stage in the Dockerfile
restart: unless-stopped
volumes:
- laravel-storage-production:/var/www/storage # Mount the storage volume
env_file:
- .env
networks:
- laravel-production
healthcheck:
test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"]
interval: 10s
timeout: 5s
retries: 3
# The 'depends_on' attribute with 'condition: service_healthy' ensures that
# this service will not start until the 'postgres' service passes its health check.
# This prevents the application from trying to connect to the database before it's ready.
depends_on:
postgres:
condition: service_healthy
# The 'php-cli' service provides a command-line interface for running Artisan commands and other CLI tasks.
# -----------------------------------------------------------
# This is useful for running migrations, seeders, or any custom scripts.
# It shares the same codebase and environment as the 'php-fpm' service.
# -----------------------------------------------------------
php-cli:
build:
context: .
dockerfile: ./docker/php-cli/Dockerfile
tty: true # Enables an interactive terminal
stdin_open: true # Keeps standard input open for 'docker exec'
env_file:
- .env
networks:
- laravel-production
postgres:
image: postgres:18
restart: unless-stopped
user: postgres
ports:
- "${POSTGRES_PORT}:5432"
environment:
- POSTGRES_DB=${POSTGRES_DATABASE}
- POSTGRES_USER=${POSTGRES_USERNAME}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres-data-production:/var/lib/postgresql
networks:
- laravel-production
# Health check for PostgreSQL
# -----------------------------------------------------------
# Health checks allow Docker to determine if a service is operational.
# The 'pg_isready' command checks if PostgreSQL is ready to accept connections.
# This prevents dependent services from starting before the database is ready.
# -----------------------------------------------------------
healthcheck:
test: ["CMD", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:alpine
restart: unless-stopped # Automatically restart unless the service is explicitly stopped
networks:
- laravel-production
# Health check for Redis
# -----------------------------------------------------------
# Checks if Redis is responding to the 'PING' command.
# This ensures that the service is not only running but also operational.
# -----------------------------------------------------------
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
# Attach the service to the 'laravel-production' network.
# -----------------------------------------------------------
# This custom network allows all services within it to communicate using their service names as hostnames.
# For example, 'php-fpm' can connect to 'postgres' by using 'postgres' as the hostname.
# -----------------------------------------------------------
laravel-production:
volumes:
postgres-data-production:
laravel-storage-production:
```
> [!NOTE]
> Ensure you have an `.env` file at the root of your Laravel project with the necessary configurations to match the Docker Compose setup.
## Running your production environment
To start the production environment, run:
```console
$ docker compose -f compose.prod.yaml up --build -d
```
This command will build and start all the services in detached mode, providing a scalable and production-ready setup for your Laravel application.
## Summary
By setting up a Docker Compose environment for Laravel in production, you ensure that your application is optimized for performance, scalable, and secure. This setup makes deployments consistent and easier to manage, reducing the likelihood of errors due to differences between environments.

View File

@@ -5,10 +5,10 @@ title: Generate Docker Compose Files with Claude Code and Docker MCP Toolkit
summary: |
This guide shows how to wire Claude Code to the Docker MCP Toolkit so it can search Docker Hub images and generate complete Docker Compose stacks from natural language.
You’ll enable the Docker Hub MCP server, connect Claude Code, verify MCP access, and create a Node.js + PostgreSQL stack with a conversational prompt.
tags: [ai]
aliases:
- /guides/use-case/genai-claude-code-mcp/
params:
tags: [ai]
time: 15 minutes
---

View File

@@ -5,8 +5,8 @@ description: This guide walks through the process of setting up and utilizing a
keywords: Docker, GenAI, Retrieval-Augmented Generation, RAG, Graph Databases, Neo4j, AI, LLM
summary: |
This guide explains setting up a GenAI stack with Retrieval-Augmented Generation (RAG) and Neo4j, covering key concepts, deployment steps, and a case study. It also includes troubleshooting tips for optimizing AI performance with real-time data.
tags: [ai]
params:
tags: [ai]
time: 35 minutes
---

View File

@@ -1,20 +0,0 @@
---
title: PDF analysis and chat
description: Containerize generative AI (GenAI) apps using Docker
keywords: python, generative ai, genai, llm, neo4j, ollama, langchain
summary: |
Learn how to build a PDF bot for parsing PDF documents and generating
responses using Docker and generative AI.
tags: [ai]
aliases:
- /guides/use-case/genai-pdf-bot/
params:
time: 20 minutes
---
The generative AI (GenAI) guide teaches you how to containerize an existing GenAI application using Docker. In this guide, you’ll learn how to:
- Containerize and run a Python-based GenAI application
- Set up a local environment to run the complete GenAI stack locally for development
Start by containerizing an existing GenAI application.

View File

@@ -1,264 +0,0 @@
---
title: Containerize a generative AI application
linkTitle: Containerize your app
weight: 10
keywords: python, generative ai, genai, llm, neo4j, ollama, containerize, initialize, langchain, openai
description: Learn how to containerize a generative AI (GenAI) application.
aliases:
- /guides/use-case/genai-pdf-bot/containerize/
---
## Prerequisites
> [!NOTE]
>
> GenAI applications can often benefit from GPU acceleration. Currently Docker Desktop supports GPU acceleration only on [Windows with the WSL2 backend](/manuals/desktop/features/gpu.md#using-nvidia-gpus-with-wsl2). Linux users can also access GPU acceleration using a native installation of the [Docker Engine](/manuals/engine/install/_index.md).
- You have installed the latest version of [Docker Desktop](/get-started/get-docker.md) or, if you are a Linux user and are planning to use GPU acceleration, [Docker Engine](/manuals/engine/install/_index.md). Docker adds new features regularly and some parts of this guide may work only with the latest version of Docker Desktop.
- You have a [git client](https://git-scm.com/downloads). The examples in this section use a command-line based git client, but you can use any client.
## Overview
This section walks you through containerizing a generative AI (GenAI) application using Docker Desktop.
> [!NOTE]
>
> You can see more samples of containerized GenAI applications in the [GenAI Stack](https://github.com/docker/genai-stack) demo applications.
## Get the sample application
The sample application used in this guide is a modified version of the PDF Reader application from the [GenAI Stack](https://github.com/docker/genai-stack) demo applications. The application is a full stack Python application that lets you ask questions about a PDF file.
The application uses [LangChain](https://www.langchain.com/) for orchestration, [Streamlit](https://streamlit.io/) for the UI, [Ollama](https://ollama.ai/) to run the LLM, and [Neo4j](https://neo4j.com/) to store vectors.
Clone the sample application. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/craig-osterhout/docker-genai-sample
```
You should now have the following files in your `docker-genai-sample` directory.
```text
├── docker-genai-sample/
│ ├── .gitignore
│ ├── app.py
│ ├── chains.py
│ ├── env.example
│ ├── requirements.txt
│ ├── util.py
│ ├── LICENSE
│ └── README.md
```
## Create Docker assets
Now that you have an application, you can create the necessary Docker assets to
containerize it.
> [!TIP]
>
> [Gordon](/ai/gordon/), Docker's AI assistant, can generate Docker assets for your project. Ask Gordon to create a Dockerfile, Compose file, and `.dockerignore` tailored to your application.
Create the following files in your `docker-genai-sample` directory.
```dockerfile {collapse=true,title=Dockerfile}
# syntax=docker/dockerfile:1
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/go/dockerfile-reference/
ARG PYTHON_VERSION=3.11.4
FROM python:${PYTHON_VERSION}-slim as base
# Prevents Python from writing pyc files.
ENV PYTHONDONTWRITEBYTECODE=1
# Keeps Python from buffering stdout and stderr to avoid situations where
# the application crashes without emitting any logs due to buffering.
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.
# Leverage a bind mount to requirements.txt to avoid having to copy them into
# into this layer.
RUN --mount=type=cache,target=/root/.cache/pip \
--mount=type=bind,source=requirements.txt,target=requirements.txt \
python -m pip install -r requirements.txt
# Switch to the non-privileged user to run the application.
USER appuser
# Copy the source code into the container.
COPY . .
# Expose the port that the application listens on.
EXPOSE 8000
# Run the application.
CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0", "--server.port=8000"]
```
```yaml {collapse=true,title=compose.yaml}
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
ports:
- 8000:8000
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
```
```text {collapse=true,title=".dockerignore"}
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.DS_Store
**/__pycache__
**/.venv
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
```
You should now have the following contents in your `docker-genai-sample`
directory.
```text
├── docker-genai-sample/
│ ├── .dockerignore
│ ├── .gitignore
│ ├── app.py
│ ├── chains.py
│ ├── compose.yaml
│ ├── env.example
│ ├── requirements.txt
│ ├── util.py
│ ├── Dockerfile
│ ├── LICENSE
│ └── README.md
```
To learn more about these files, see the following:
- [Dockerfile](../../../reference/dockerfile.md)
- [.dockerignore](../../../reference/dockerfile.md#dockerignore-file)
- [compose.yaml](/reference/compose-file/_index.md)
## Run the application
Inside the `docker-genai-sample` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Docker builds and runs your application. Depending on your network connection, it may take several minutes to download all the dependencies. You'll see a message like the following in the terminal when the application is running.
```console
server-1 | You can now view your Streamlit app in your browser.
server-1 |
server-1 | URL: http://0.0.0.0:8000
server-1 |
```
Open a browser and view the application at [http://localhost:8000](http://localhost:8000). You should see a simple Streamlit application. The application may take a few minutes to download the embedding model. While the download is in progress, **Running** appears in the top-right corner.
The application requires a Neo4j database service and an LLM service to
function. If you have access to services that you ran outside of Docker, specify
the connection information and try it out. If you don't have the services
running, continue with this guide to learn how you can run some or all of these
services with Docker.
In the terminal, press `ctrl`+`c` to stop the application.
## Summary
In this section, you learned how you can containerize and run your GenAI
application using Docker.
## Next steps
In the next section, you'll learn how you can run your application, database, and LLM service all locally using Docker.

View File

@@ -1,261 +0,0 @@
---
title: Use containers for generative AI development
linkTitle: Develop your app
weight: 20
keywords: python, local, development, generative ai, genai, llm, neo4j, ollama, langchain, openai
description: Learn how to develop your generative AI (GenAI) application locally.
aliases:
- /guides/use-case/genai-pdf-bot/develop/
---
## Prerequisites
Complete [Containerize a generative AI application](containerize.md).
## Overview
In this section, you'll learn how to set up a development environment to access all the services that your generative AI (GenAI) application needs. This includes:
- Adding a local database
- Adding a local or remote LLM service
> [!NOTE]
>
> You can see more samples of containerized GenAI applications in the [GenAI Stack](https://github.com/docker/genai-stack) demo applications.
## Add a local database
You can use containers to set up local services, like a database. In this section, you'll update the `compose.yaml` file to define a database service. In addition, you'll specify an environment variables file to load the database connection information rather than manually entering the information every time.
To run the database service:
1. In the cloned repository's directory, rename `env.example` file to `.env`.
This file contains the environment variables that the containers will use.
2. In the cloned repository's directory, open the `compose.yaml` file in an IDE or text editor.
3. In the `compose.yaml` file, add the following:
- Add instructions to run a Neo4j database
- Specify the environment file under the server service in order to pass in the environment variables for the connection
The following is the updated `compose.yaml` file. All comments have been removed.
```yaml{hl_lines=["7-23"]}
services:
server:
build:
context: .
ports:
- 8000:8000
env_file:
- .env
depends_on:
database:
condition: service_healthy
database:
image: neo4j:5.11
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=${NEO4J_USERNAME}/${NEO4J_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"]
interval: 5s
timeout: 3s
retries: 5
```
> [!NOTE]
>
> To learn more about Neo4j, see the [Neo4j Official Docker Image](https://hub.docker.com/_/neo4j).
4. Run the application. Inside the `docker-genai-sample` directory,
run the following command in a terminal.
```console
$ docker compose up --build
```
5. Access the application. Open a browser and view the application at [http://localhost:8000](http://localhost:8000). You should see a simple Streamlit application. Note that asking questions to a PDF will cause the application to fail because the LLM service specified in the `.env` file isn't running yet.
6. Stop the application. In the terminal, press `ctrl`+`c` to stop the application.
## Add a local or remote LLM service
The sample application supports both [Ollama](https://ollama.ai/) and [OpenAI](https://openai.com/). This guide provides instructions for the following scenarios:
- Run Ollama in a container
- Run Ollama outside of a container
- Use OpenAI
While all platforms can use any of the previous scenarios, the performance and
GPU support may vary. You can use the following guidelines to help you choose the appropriate option:
- Run Ollama in a container if you're on Linux, and using a native installation of the Docker Engine, or Windows 10/11, and using Docker Desktop, you
have a CUDA-supported GPU, and your system has at least 8 GB of RAM.
- Run Ollama outside of a container if you're on an Apple silicon Mac.
- Use OpenAI if the previous two scenarios don't apply to you.
Choose one of the following options for your LLM service.
{{< tabs >}}
{{< tab name="Run Ollama in a container" >}}
When running Ollama in a container, you should have a CUDA-supported GPU. While you can run Ollama in a container without a supported GPU, the performance may not be acceptable. Only Linux and Windows 11 support GPU access to containers.
To run Ollama in a container and provide GPU access:
1. Install the prerequisites.
- For Docker Engine on Linux, install the [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit).
- For Docker Desktop on Windows 10/11, install the latest [NVIDIA driver](https://www.nvidia.com/Download/index.aspx) and make sure you are using the [WSL2 backend](/manuals/desktop/features/wsl/_index.md#turn-on-docker-desktop-wsl-2)
2. Add the Ollama service and a volume in your `compose.yaml`. The following is
the updated `compose.yaml`:
```yaml {hl_lines=["24-38"]}
services:
server:
build:
context: .
ports:
- 8000:8000
env_file:
- .env
depends_on:
database:
condition: service_healthy
database:
image: neo4j:5.11
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=${NEO4J_USERNAME}/${NEO4J_PASSWORD}
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider localhost:7474 || exit 1",
]
interval: 5s
timeout: 3s
retries: 5
ollama:
image: ollama/ollama:latest
ports:
- "11434:11434"
volumes:
- ollama_volume:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
volumes:
ollama_volume:
```
> [!NOTE]
>
> For more details about the Compose instructions, see [Turn on GPU access with Docker Compose](/manuals/compose/how-tos/gpu-support.md).
3. Add the ollama-pull service to your `compose.yaml` file. This service uses
the `docker/genai:ollama-pull` image, based on the GenAI Stack's
[pull_model.Dockerfile](https://github.com/docker/genai-stack/blob/main/pull_model.Dockerfile).
The service will automatically pull the model for your Ollama
container. The following is the updated section of the `compose.yaml` file:
```yaml {hl_lines=["12-17"]}
services:
server:
build:
context: .
ports:
- 8000:8000
env_file:
- .env
depends_on:
database:
condition: service_healthy
ollama-pull:
condition: service_completed_successfully
ollama-pull:
image: docker/genai:ollama-pull
env_file:
- .env
# ...
```
{{< /tab >}}
{{< tab name="Run Ollama outside of a container" >}}
To run Ollama outside of a container:
1. [Install](https://github.com/jmorganca/ollama) and run Ollama on your host
machine.
2. Update the `OLLAMA_BASE_URL` value in your `.env` file to
`http://host.docker.internal:11434`.
3. Pull the model to Ollama using the following command.
```console
$ ollama pull llama2
```
{{< /tab >}}
{{< tab name="Use OpenAI" >}}
> [!IMPORTANT]
>
> Using OpenAI requires an [OpenAI account](https://platform.openai.com/login). OpenAI is a third-party hosted service and charges may apply.
1. Update the `LLM` value in your `.env` file to
`gpt-3.5`.
2. Uncomment and update the `OPENAI_API_KEY` value in your `.env` file to
your [OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key).
{{< /tab >}}
{{< /tabs >}}
## Run your GenAI application
At this point, you have the following services in your Compose file:
- Server service for your main GenAI application
- Database service to store vectors in a Neo4j database
- (optional) Ollama service to run the LLM
- (optional) Ollama-pull service to automatically pull the model for the Ollama
service
To run all the services, run the following command in your `docker-genai-sample`
directory:
```console
$ docker compose up --build
```
If your Compose file has the ollama-pull service, it may take several minutes for the ollama-pull service to pull the model. The ollama-pull service will continuously update the console with its status. After pulling the model, the ollama-pull service container will stop and you can access the application.
Once the application is running, open a browser and access the application at [http://localhost:8000](http://localhost:8000).
Upload a PDF file, for example the [Docker CLI Cheat Sheet](https://docs.docker.com/get-started/docker_cheatsheet.pdf), and ask a question about the PDF.
Depending on your system and the LLM service that you chose, it may take several
minutes to answer. If you are using Ollama and the performance isn't
acceptable, try using OpenAI.
## Summary
In this section, you learned how to set up a development environment to provide
access all the services that your GenAI application needs.
Related information:
- [Dockerfile reference](../../../reference/dockerfile.md)
- [Compose file reference](/reference/compose-file/_index.md)
- [Ollama Docker image](https://hub.docker.com/r/ollama/ollama)
- [Neo4j Official Docker Image](https://hub.docker.com/_/neo4j)
- [GenAI Stack demo applications](https://github.com/docker/genai-stack)
## Next steps
See samples of more GenAI applications in the [GenAI Stack demo applications](https://github.com/docker/genai-stack).

View File

@@ -0,0 +1,534 @@
---
title: PDF analysis and chat
description: Containerize generative AI (GenAI) apps using Docker
keywords: python, generative ai, genai, llm, neo4j, ollama, langchain
summary: |
Learn how to build a PDF bot for parsing PDF documents and generating
responses using Docker and generative AI.
aliases:
- /guides/use-case/genai-pdf-bot/
- /guides/genai-pdf-bot/containerize/
- /guides/genai-pdf-bot/develop/
params:
tags: [ai]
time: 20 minutes
---
The generative AI (GenAI) guide teaches you how to containerize an existing GenAI application using Docker. In this guide, you’ll learn how to:
- Containerize and run a Python-based GenAI application
- Set up a local environment to run the complete GenAI stack locally for development
Start by containerizing an existing GenAI application.
## Containerize a generative AI application
### Prerequisites
> [!NOTE]
>
> GenAI applications can often benefit from GPU acceleration. Currently Docker Desktop supports GPU acceleration only on [Windows with the WSL2 backend](/manuals/desktop/features/gpu.md#using-nvidia-gpus-with-wsl2). Linux users can also access GPU acceleration using a native installation of the [Docker Engine](/manuals/engine/install/_index.md).
- You have installed the latest version of [Docker Desktop](/get-started/get-docker.md) or, if you are a Linux user and are planning to use GPU acceleration, [Docker Engine](/manuals/engine/install/_index.md). Docker adds new features regularly and some parts of this guide may work only with the latest version of Docker Desktop.
- You have a [git client](https://git-scm.com/downloads). The examples in this section use a command-line based git client, but you can use any client.
### Overview
This section walks you through containerizing a generative AI (GenAI) application using Docker Desktop.
> [!NOTE]
>
> You can see more samples of containerized GenAI applications in the [GenAI Stack](https://github.com/docker/genai-stack) demo applications.
### Get the sample application
The sample application used in this guide is a modified version of the PDF Reader application from the [GenAI Stack](https://github.com/docker/genai-stack) demo applications. The application is a full stack Python application that lets you ask questions about a PDF file.
The application uses [LangChain](https://www.langchain.com/) for orchestration, [Streamlit](https://streamlit.io/) for the UI, [Ollama](https://ollama.ai/) to run the LLM, and [Neo4j](https://neo4j.com/) to store vectors.
Clone the sample application. Open a terminal, change directory to a directory that you want to work in, and run the following command to clone the repository:
```console
$ git clone https://github.com/craig-osterhout/docker-genai-sample
```
You should now have the following files in your `docker-genai-sample` directory.
```text
├── docker-genai-sample/
│ ├── .gitignore
│ ├── app.py
│ ├── chains.py
│ ├── env.example
│ ├── requirements.txt
│ ├── util.py
│ ├── LICENSE
│ └── README.md
```
### Create Docker assets
Now that you have an application, you can create the necessary Docker assets to
containerize it.
> [!TIP]
>
> [Gordon](/ai/gordon/), Docker's AI assistant, can generate Docker assets for your project. Ask Gordon to create a Dockerfile, Compose file, and `.dockerignore` tailored to your application.
Create the following files in your `docker-genai-sample` directory.
```dockerfile {collapse=true,title=Dockerfile}
# syntax=docker/dockerfile:1
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/go/dockerfile-reference/
ARG PYTHON_VERSION=3.11.4
FROM python:${PYTHON_VERSION}-slim as base
# Prevents Python from writing pyc files.
ENV PYTHONDONTWRITEBYTECODE=1
# Keeps Python from buffering stdout and stderr to avoid situations where
# the application crashes without emitting any logs due to buffering.
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.
# Leverage a bind mount to requirements.txt to avoid having to copy them into
# into this layer.
RUN --mount=type=cache,target=/root/.cache/pip \
--mount=type=bind,source=requirements.txt,target=requirements.txt \
python -m pip install -r requirements.txt
# Switch to the non-privileged user to run the application.
USER appuser
# Copy the source code into the container.
COPY . .
# Expose the port that the application listens on.
EXPOSE 8000
# Run the application.
CMD ["streamlit", "run", "app.py", "--server.address=0.0.0.0", "--server.port=8000"]
```
```yaml {collapse=true,title=compose.yaml}
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker Compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/
# Here the instructions define your application as a service called "server".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
server:
build:
context: .
ports:
- 8000:8000
# The commented out section below is an example of how to define a PostgreSQL
# database that your application can use. `depends_on` tells Docker Compose to
# start the database before your application. The `db-data` volume persists the
# database data between container restarts. The `db-password` secret is used
# to set the database password. You must create `db/password.txt` and add
# a password of your choosing to it before running `docker compose up`.
# depends_on:
# db:
# condition: service_healthy
# db:
# image: postgres
# restart: always
# user: postgres
# secrets:
# - db-password
# volumes:
# - db-data:/var/lib/postgresql/data
# environment:
# - POSTGRES_DB=example
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
# expose:
# - 5432
# healthcheck:
# test: [ "CMD", "pg_isready" ]
# interval: 10s
# timeout: 5s
# retries: 5
# volumes:
# db-data:
# secrets:
# db-password:
# file: db/password.txt
```
```text {collapse=true,title=".dockerignore"}
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.DS_Store
**/__pycache__
**/.venv
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
```
You should now have the following contents in your `docker-genai-sample`
directory.
```text
├── docker-genai-sample/
│ ├── .dockerignore
│ ├── .gitignore
│ ├── app.py
│ ├── chains.py
│ ├── compose.yaml
│ ├── env.example
│ ├── requirements.txt
│ ├── util.py
│ ├── Dockerfile
│ ├── LICENSE
│ └── README.md
```
To learn more about these files, see the following:
- [Dockerfile](../../../reference/dockerfile.md)
- [.dockerignore](../../../reference/dockerfile.md#dockerignore-file)
- [compose.yaml](/reference/compose-file/_index.md)
### Run the application
Inside the `docker-genai-sample` directory, run the following command in a
terminal.
```console
$ docker compose up --build
```
Docker builds and runs your application. Depending on your network connection, it may take several minutes to download all the dependencies. You'll see a message like the following in the terminal when the application is running.
```console
server-1 | You can now view your Streamlit app in your browser.
server-1 |
server-1 | URL: http://0.0.0.0:8000
server-1 |
```
Open a browser and view the application at [http://localhost:8000](http://localhost:8000). You should see a simple Streamlit application. The application may take a few minutes to download the embedding model. While the download is in progress, **Running** appears in the top-right corner.
The application requires a Neo4j database service and an LLM service to
function. If you have access to services that you ran outside of Docker, specify
the connection information and try it out. If you don't have the services
running, continue with this guide to learn how you can run some or all of these
services with Docker.
In the terminal, press `ctrl`+`c` to stop the application.
### Summary
In this section, you learned how you can containerize and run your GenAI
application using Docker.
### Next steps
In the next section, you'll learn how you can run your application, database, and LLM service all locally using Docker.
## Use containers for generative AI development
### Prerequisites
Complete [Containerize a generative AI application](./).
### Overview
In this section, you'll learn how to set up a development environment to access all the services that your generative AI (GenAI) application needs. This includes:
- Adding a local database
- Adding a local or remote LLM service
> [!NOTE]
>
> You can see more samples of containerized GenAI applications in the [GenAI Stack](https://github.com/docker/genai-stack) demo applications.
### Add a local database
You can use containers to set up local services, like a database. In this section, you'll update the `compose.yaml` file to define a database service. In addition, you'll specify an environment variables file to load the database connection information rather than manually entering the information every time.
To run the database service:
1. In the cloned repository's directory, rename `env.example` file to `.env`.
This file contains the environment variables that the containers will use.
2. In the cloned repository's directory, open the `compose.yaml` file in an IDE or text editor.
3. In the `compose.yaml` file, add the following:
- Add instructions to run a Neo4j database
- Specify the environment file under the server service in order to pass in the environment variables for the connection
The following is the updated `compose.yaml` file. All comments have been removed.
```yaml{hl_lines=["7-23"]}
services:
server:
build:
context: .
ports:
- 8000:8000
env_file:
- .env
depends_on:
database:
condition: service_healthy
database:
image: neo4j:5.11
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=${NEO4J_USERNAME}/${NEO4J_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"]
interval: 5s
timeout: 3s
retries: 5
```
> [!NOTE]
>
> To learn more about Neo4j, see the [Neo4j Official Docker Image](https://hub.docker.com/_/neo4j).
4. Run the application. Inside the `docker-genai-sample` directory,
run the following command in a terminal.
```console
$ docker compose up --build
```
5. Access the application. Open a browser and view the application at [http://localhost:8000](http://localhost:8000). You should see a simple Streamlit application. Note that asking questions to a PDF will cause the application to fail because the LLM service specified in the `.env` file isn't running yet.
6. Stop the application. In the terminal, press `ctrl`+`c` to stop the application.
### Add a local or remote LLM service
The sample application supports both [Ollama](https://ollama.ai/) and [OpenAI](https://openai.com/). This guide provides instructions for the following scenarios:
- Run Ollama in a container
- Run Ollama outside of a container
- Use OpenAI
While all platforms can use any of the previous scenarios, the performance and
GPU support may vary. You can use the following guidelines to help you choose the appropriate option:
- Run Ollama in a container if you're on Linux, and using a native installation of the Docker Engine, or Windows 10/11, and using Docker Desktop, you
have a CUDA-supported GPU, and your system has at least 8 GB of RAM.
- Run Ollama outside of a container if you're on an Apple silicon Mac.
- Use OpenAI if the previous two scenarios don't apply to you.
Choose one of the following options for your LLM service.
{{< tabs >}}
{{< tab name="Run Ollama in a container" >}}
When running Ollama in a container, you should have a CUDA-supported GPU. While you can run Ollama in a container without a supported GPU, the performance may not be acceptable. Only Linux and Windows 11 support GPU access to containers.
To run Ollama in a container and provide GPU access:
1. Install the prerequisites.
- For Docker Engine on Linux, install the [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-container-toolkit).
- For Docker Desktop on Windows 10/11, install the latest [NVIDIA driver](https://www.nvidia.com/Download/index.aspx) and make sure you are using the [WSL2 backend](/manuals/desktop/features/wsl/_index.md#turn-on-docker-desktop-wsl-2)
2. Add the Ollama service and a volume in your `compose.yaml`. The following is
the updated `compose.yaml`:
```yaml {hl_lines=["24-38"]}
services:
server:
build:
context: .
ports:
- 8000:8000
env_file:
- .env
depends_on:
database:
condition: service_healthy
database:
image: neo4j:5.11
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=${NEO4J_USERNAME}/${NEO4J_PASSWORD}
healthcheck:
test:
[
"CMD-SHELL",
"wget --no-verbose --tries=1 --spider localhost:7474 || exit 1",
]
interval: 5s
timeout: 3s
retries: 5
ollama:
image: ollama/ollama:latest
ports:
- "11434:11434"
volumes:
- ollama_volume:/root/.ollama
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
volumes:
ollama_volume:
```
> [!NOTE]
>
> For more details about the Compose instructions, see [Turn on GPU access with Docker Compose](/manuals/compose/how-tos/gpu-support.md).
3. Add the ollama-pull service to your `compose.yaml` file. This service uses
the `docker/genai:ollama-pull` image, based on the GenAI Stack's
[pull_model.Dockerfile](https://github.com/docker/genai-stack/blob/main/pull_model.Dockerfile).
The service will automatically pull the model for your Ollama
container. The following is the updated section of the `compose.yaml` file:
```yaml {hl_lines=["12-17"]}
services:
server:
build:
context: .
ports:
- 8000:8000
env_file:
- .env
depends_on:
database:
condition: service_healthy
ollama-pull:
condition: service_completed_successfully
ollama-pull:
image: docker/genai:ollama-pull
env_file:
- .env
# ...
```
{{< /tab >}}
{{< tab name="Run Ollama outside of a container" >}}
To run Ollama outside of a container:
1. [Install](https://github.com/jmorganca/ollama) and run Ollama on your host
machine.
2. Update the `OLLAMA_BASE_URL` value in your `.env` file to
`http://host.docker.internal:11434`.
3. Pull the model to Ollama using the following command.
```console
$ ollama pull llama2
```
{{< /tab >}}
{{< tab name="Use OpenAI" >}}
> [!IMPORTANT]
>
> Using OpenAI requires an [OpenAI account](https://platform.openai.com/login). OpenAI is a third-party hosted service and charges may apply.
1. Update the `LLM` value in your `.env` file to
`gpt-3.5`.
2. Uncomment and update the `OPENAI_API_KEY` value in your `.env` file to
your [OpenAI API key](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key).
{{< /tab >}}
{{< /tabs >}}
### Run your GenAI application
At this point, you have the following services in your Compose file:
- Server service for your main GenAI application
- Database service to store vectors in a Neo4j database
- (optional) Ollama service to run the LLM
- (optional) Ollama-pull service to automatically pull the model for the Ollama
service
To run all the services, run the following command in your `docker-genai-sample`
directory:
```console
$ docker compose up --build
```
If your Compose file has the ollama-pull service, it may take several minutes for the ollama-pull service to pull the model. The ollama-pull service will continuously update the console with its status. After pulling the model, the ollama-pull service container will stop and you can access the application.
Once the application is running, open a browser and access the application at [http://localhost:8000](http://localhost:8000).
Upload a PDF file, for example the [Docker CLI Cheat Sheet](https://docs.docker.com/get-started/docker_cheatsheet.pdf), and ask a question about the PDF.
Depending on your system and the LLM service that you chose, it may take several
minutes to answer. If you are using Ollama and the performance isn't
acceptable, try using OpenAI.
### Summary
In this section, you learned how to set up a development environment to provide
access all the services that your GenAI application needs.
Related information:
- [Dockerfile reference](../../../reference/dockerfile.md)
- [Compose file reference](/reference/compose-file/_index.md)
- [Ollama Docker image](https://hub.docker.com/r/ollama/ollama)
- [Neo4j Official Docker Image](https://hub.docker.com/_/neo4j)
- [GenAI Stack demo applications](https://github.com/docker/genai-stack)
### Next steps
See samples of more GenAI applications in the [GenAI Stack demo applications](https://github.com/docker/genai-stack).

View File

@@ -6,10 +6,10 @@ keywords: python, generative ai, genai, llm, whisper, pinecone, openai, whisper
summary: |
Learn how to build and deploy a generative AI video analysis and
transcription bot using Docker.
tags: [ai]
aliases:
- /guides/use-case/genai-video-bot/
params:
tags: [ai]
time: 20 minutes
---
@@ -78,14 +78,14 @@ addition, it provides timestamps from the video that can help you find the sourc
called `.env` and specify your API keys inside. The following is the contents of the `.env.example` file that you can refer to as an example.
```text
#----------------------------------------------------------------------------
#-------------------------------------------------------------------------
# OpenAI
#----------------------------------------------------------------------------
#-------------------------------------------------------------------------
OPENAI_TOKEN=your-api-key # Replace your-api-key with your personal API key
#----------------------------------------------------------------------------
#-------------------------------------------------------------------------
# Pinecone
#----------------------------------------------------------------------------
#-------------------------------------------------------------------------
PINECONE_TOKEN=your-api-key # Replace your-api-key with your personal API key
```

View File

@@ -5,7 +5,7 @@ summary: |
Learn how to automate image build and push with GitHub Actions.
keywords: github actions, ci/cd, docker hub, build and push, automation, workflows
params:
tags: [devops]
tags: [cicd]
time: 10 minutes
---
@@ -252,5 +252,6 @@ additional features based on your project's needs, such as
### Further reading
- Learn more about advanced configurations and examples in the [Docker Build GitHub Actions](/manuals/build/ci/github-actions/_index.md) section.
- For more complex build setups, you may want to consider [Bake](/manuals/build/bake/_index.md). (See also the [Mastering Buildx Bake guide](/guides/bake/index.md).)
- For more complex build setups, you may want to consider [Bake](/manuals/build/bake/_index.md). (See also the [Mastering Buildx Bake guide](/guides/bake/).)
- Learn about Docker's managed build service, designed for faster, multi-platform builds, see [Docker Build Cloud](/guides/docker-build-cloud/_index.md).

View File

@@ -1,56 +0,0 @@
---
title: How to build an AI-powered code quality workflow with SonarQube and E2B
linkTitle: AI-powered code quality
summary: Build AI-powered code quality workflows using E2B sandboxes with Docker's MCP catalog to automate GitHub and SonarQube integration.
description: Learn how to create E2B sandboxes with MCP servers, analyze code quality with SonarQube, and generate quality-gated pull requests using GitHub—all through natural language interactions with Claude.
keywords: sonarqube, e2b, sandboxes, mcp, github, code quality, ai workflow, claude
tags: [devops]
params:
time: 40 minutes
image:
resource_links:
- title: E2B Documentation
url: https://e2b.dev/docs
- title: Docker MCP Catalog
url: https://hub.docker.com/mcp
- title: Sandboxes
url: https://docs.docker.com/ai/mcp-catalog-and-toolkit/sandboxes/
---
This guide demonstrates how to build an AI-powered code quality workflow using
[E2B sandboxes](https://e2b.dev/docs) with Docker’s MCP catalog. You’ll create
a system that automatically analyzes code quality issues in GitHub repositories
using SonarQube, then generate pull requests with fixes.
## What you'll build
You’ll build a Node.js script that spins up an E2B sandbox, connects GitHub and
SonarQube MCP servers, and uses Claude Code to analyze code quality and propose
improvements. The MCP servers are containerized and run as part of the E2B
sandbox.
## What you'll learn
In this guide, you'll learn:
- How to create E2B sandboxes with multiple MCP servers
- How to configure GitHub and SonarQube MCP servers for AI workflows
- How to use Claude Code inside sandboxes to interact with external tools
- How to build automated code review workflows that create quality-gated
pull requests
## Why use E2B sandboxes?
Running this workflow in E2B sandboes provides several advantages over
local execution:
- Security: AI-generated code runs in isolated containers, protecting your
local environment and credentials
- Zero setup: No need to install SonarQube, GitHub CLI, or manage dependencies
locally
- Scalability: Resource-intensive operations like code scanning run in the
cloud without consuming local resources
## Learn more
Read Docker's blog post: [Docker + E2B: Building the Future of Trusted AI](https://www.docker.com/blog/docker-e2b-building-the-future-of-trusted-ai/).

View File

@@ -1,182 +0,0 @@
---
title: Customize a code quality check workflow
linkTitle: Customize workflow
summary: Adapt your GitHub and SonarQube workflow to focus on specific quality issues, integrate with CI/CD, and set custom thresholds.
description: Learn how to customize prompts for specific quality issues, filter by file patterns, set quality thresholds, and integrate your workflow with GitHub Actions for automated code quality checks.
keywords: sonarqube, e2b, mcp, github actions, code quality, customization, ci/cd
weight: 20
---
Now that you understand the basics of automating code quality workflows with
GitHub and SonarQube in E2B sandboxes, you can customize the workflow
for your needs.
## Focus on specific quality issues
Modify the prompt to prioritize certain issue types:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
const prompt = `Using SonarQube and GitHub MCP tools:
Focus only on:
- Security vulnerabilities (CRITICAL priority)
- Bugs (HIGH priority)
- Skip code smells for this iteration
Analyze "${repoPath}" and fix the highest priority issues first.`;
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
prompt = f"""Using SonarQube and GitHub MCP tools:
Focus only on:
- Security vulnerabilities (CRITICAL priority)
- Bugs (HIGH priority)
- Skip code smells for this iteration
Analyze "{repo_path}" and fix the highest priority issues first."""
```
{{< /tab >}}
{{< /tabs >}}
## Integrate with CI/CD
Add this workflow to GitHub Actions to run automatically on pull requests:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```yaml
name: Automated quality checks
on:
pull_request:
types: [opened, synchronize]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@{{% param "checkout_action_version" %}}
- uses: actions/setup-node@v5
with:
node-version: "24"
- run: npm install
- run: npx tsx 06-quality-gated-pr.ts
env:
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.event.repository.name }}
SONARQUBE_ORG: your-org-key
```
{{< /tab >}}
{{< tab name="Python" >}}
```yaml
name: Automated quality checks
on:
pull_request:
types: [opened, synchronize]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@{{% param "checkout_action_version" %}}
- uses: actions/setup-python@v6
with:
python-version: "3.14"
- run: pip install e2b python-dotenv
- run: python 06_quality_gated_pr.py
env:
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.event.repository.name }}
SONARQUBE_ORG: your-org-key
```
{{< /tab >}}
{{< /tabs >}}
## Filter by file patterns
Target specific parts of your codebase:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
const prompt = `Analyze code quality but only consider:
- Files in src/**/*.js
- Exclude test files (*.test.js, *.spec.js)
- Exclude build artifacts in dist/
Focus on production code only.`;
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
prompt = """Analyze code quality but only consider:
- Files in src/**/*.js
- Exclude test files (*.test.js, *.spec.js)
- Exclude build artifacts in dist/
Focus on production code only."""
```
{{< /tab >}}
{{< /tabs >}}
## Set quality thresholds
Define when PRs should be created:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
const prompt = `Quality gate thresholds:
- Only create PR if:
* Bug count decreases by at least 1
* No new security vulnerabilities introduced
* Code coverage does not decrease
* Technical debt reduces by at least 15 minutes
If changes do not meet these thresholds, explain why and skip PR creation.`;
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
prompt = """Quality gate thresholds:
- Only create PR if:
* Bug count decreases by at least 1
* No new security vulnerabilities introduced
* Code coverage does not decrease
* Technical debt reduces by at least 15 minutes
If changes do not meet these thresholds, explain why and skip PR creation."""
```
{{< /tab >}}
{{< /tabs >}}
## Next steps
Learn how to troubleshoot common issues.

View File

@@ -1,12 +1,60 @@
---
title: Build a code quality check workflow
linkTitle: Build workflow
summary: Learn to use GitHub and SonarQube MCP servers in E2B sandboxes through progressive examples.
description: Create E2B sandboxes, discover MCP tools, test individual operations, and build complete quality-gated PR workflows.
keywords: sonarqube, e2b, mcp, github, code quality, pull requests, workflow
weight: 10
title: How to build an AI-powered code quality workflow with SonarQube and E2B
linkTitle: AI-powered code quality
summary: Build AI-powered code quality workflows using E2B sandboxes with Docker's MCP catalog to automate GitHub and SonarQube integration.
description: Learn how to create E2B sandboxes with MCP servers, analyze code quality with SonarQube, and generate quality-gated pull requests using GitHub—all through natural language interactions with Claude.
keywords: sonarqube, e2b, sandboxes, mcp, github, code quality, ai workflow, claude
aliases:
- /guides/github-sonarqube-sandbox/customize/
- /guides/github-sonarqube-sandbox/troubleshoot/
- /guides/github-sonarqube-sandbox/workflow/
params:
tags: [cicd]
time: 40 minutes
image:
---
This guide demonstrates how to build an AI-powered code quality workflow using
[E2B sandboxes](https://e2b.dev/docs) with Docker’s MCP catalog. You’ll create
a system that automatically analyzes code quality issues in GitHub repositories
using SonarQube, then generate pull requests with fixes.
## What you'll build
You’ll build a Node.js script that spins up an E2B sandbox, connects GitHub and
SonarQube MCP servers, and uses Claude Code to analyze code quality and propose
improvements. The MCP servers are containerized and run as part of the E2B
sandbox.
## What you'll learn
In this guide, you'll learn:
- How to create E2B sandboxes with multiple MCP servers
- How to configure GitHub and SonarQube MCP servers for AI workflows
- How to use Claude Code inside sandboxes to interact with external tools
- How to build automated code review workflows that create quality-gated
pull requests
## Why use E2B sandboxes?
Running this workflow in E2B sandboes provides several advantages over
local execution:
- Security: AI-generated code runs in isolated containers, protecting your
local environment and credentials
- Zero setup: No need to install SonarQube, GitHub CLI, or manage dependencies
locally
- Scalability: Resource-intensive operations like code scanning run in the
cloud without consuming local resources
## Learn more
Read Docker's blog post: [Docker + E2B: Building the Future of Trusted AI](https://www.docker.com/blog/docker-e2b-building-the-future-of-trusted-ai/).
## Build a code quality check workflow
In this section, you'll build a complete code quality automation workflow
step-by-step. You'll start by creating an E2B sandbox with GitHub and
SonarQube MCP servers, then progressively add functionality until you have a
@@ -16,7 +64,7 @@ By working through each step sequentially, you'll learn how MCP servers work,
how to interact with them through Claude, and how to chain operations together
to build powerful automation workflows.
## Prerequisites
### Prerequisites
Before you begin, make sure you have:
@@ -50,7 +98,7 @@ Before you begin, make sure you have:
> use this approach with trusted code and workflows. For more information,
> see [Anthropic's guidance on container security](https://docs.anthropic.com/en/docs/claude-code/devcontainer).
## Set up your project
### Set up your project
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
@@ -167,7 +215,7 @@ Before you begin, make sure you have:
{{< /tab >}}
{{< /tabs >}}
## Step 1: Create your first sandbox
### Step 1: Create your first sandbox
Let's start by creating a sandbox and verifying the MCP servers are configured correctly.
@@ -326,7 +374,7 @@ You've just learned how to create an E2B sandbox with multiple MCP servers
configured. The `betaCreate` method initializes a cloud environment
with Claude CLI and your specified MCP servers.
## Step 2: Discover available MCP tools
### Step 2: Discover available MCP tools
MCP servers expose tools that Claude can call. The GitHub MCP server provides
repository management tools, while SonarQube provides code analysis tools.
@@ -501,7 +549,7 @@ I have access to the following MCP tools:
... (SonarQube analysis tools)
```
## Step 3: Test GitHub MCP tools
### Step 3: Test GitHub MCP tools
Let's try testing GitHub using MCP tools. Start simple by listing
repository issues.
@@ -656,7 +704,7 @@ Here are the first 10 open issues in the <your-repo> repository:
You can now send prompts to Claude and interact with GitHub through
natural language. Claude decides what tool to call based on your prompt.
## Step 4: Test SonarQube MCP tools
### Step 4: Test SonarQube MCP tools
Let's analyze code quality using SonarQube MCP tools.
@@ -850,7 +898,7 @@ You can now use SonarQube MCP tools to analyze code quality through
natural language. You can retrieve quality metrics, identify issues,
and understand what code needs fixing.
## Step 5: Create a branch and make code changes
### Step 5: Create a branch and make code changes
Now, let's teach Claude to fix code based on quality issues discovered
by SonarQube.
@@ -1068,7 +1116,7 @@ The fix is ready for review and can be merged to improve the code quality of the
You can now use GitHub and SonarQube MCP tools in the same workflow to read
files, make code changes, and commit them.
## Step 6: Create quality-gated pull requests
### Step 6: Create quality-gated pull requests
Finally, let's build the complete workflow: analyze quality, fix issues,
and create a PR only if improvements are made.
@@ -1373,7 +1421,7 @@ You've now built a complete, multi-step workflow with conditional logic.
Claude analyzes quality with SonarQube, makes fixes using GitHub tools,
verifies improvements, and only creates a PR if quality actually improves.
## Step 7: Add error handling
### Step 7: Add error handling
Production workflows need error handling. Let's make the workflow more robust.
@@ -1583,6 +1631,510 @@ python 07_robust_workflow.py
Claude will run the entire workflow, and if it encounters an error, respond
with robust error messaging.
## Next steps
### Next steps
In the next section, you'll customize your workflow for your needs.
## Customize a code quality check workflow
Now that you understand the basics of automating code quality workflows with
GitHub and SonarQube in E2B sandboxes, you can customize the workflow
for your needs.
### Focus on specific quality issues
Modify the prompt to prioritize certain issue types:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
const prompt = `Using SonarQube and GitHub MCP tools:
Focus only on:
- Security vulnerabilities (CRITICAL priority)
- Bugs (HIGH priority)
- Skip code smells for this iteration
Analyze "${repoPath}" and fix the highest priority issues first.`;
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
prompt = f"""Using SonarQube and GitHub MCP tools:
Focus only on:
- Security vulnerabilities (CRITICAL priority)
- Bugs (HIGH priority)
- Skip code smells for this iteration
Analyze "{repo_path}" and fix the highest priority issues first."""
```
{{< /tab >}}
{{< /tabs >}}
### Integrate with CI/CD
Add this workflow to GitHub Actions to run automatically on pull requests:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```yaml
name: Automated quality checks
on:
pull_request:
types: [opened, synchronize]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@{{% param "checkout_action_version" %}}
- uses: actions/setup-node@v5
with:
node-version: "24"
- run: npm install
- run: npx tsx 06-quality-gated-pr.ts
env:
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.event.repository.name }}
SONARQUBE_ORG: your-org-key
```
{{< /tab >}}
{{< tab name="Python" >}}
```yaml
name: Automated quality checks
on:
pull_request:
types: [opened, synchronize]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@{{% param "checkout_action_version" %}}
- uses: actions/setup-python@v6
with:
python-version: "3.14"
- run: pip install e2b python-dotenv
- run: python 06_quality_gated_pr.py
env:
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONARQUBE_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.event.repository.name }}
SONARQUBE_ORG: your-org-key
```
{{< /tab >}}
{{< /tabs >}}
### Filter by file patterns
Target specific parts of your codebase:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
const prompt = `Analyze code quality but only consider:
- Files in src/**/*.js
- Exclude test files (*.test.js, *.spec.js)
- Exclude build artifacts in dist/
Focus on production code only.`;
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
prompt = """Analyze code quality but only consider:
- Files in src/**/*.js
- Exclude test files (*.test.js, *.spec.js)
- Exclude build artifacts in dist/
Focus on production code only."""
```
{{< /tab >}}
{{< /tabs >}}
### Set quality thresholds
Define when PRs should be created:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
const prompt = `Quality gate thresholds:
- Only create PR if:
* Bug count decreases by at least 1
* No new security vulnerabilities introduced
* Code coverage does not decrease
* Technical debt reduces by at least 15 minutes
If changes do not meet these thresholds, explain why and skip PR creation.`;
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
prompt = """Quality gate thresholds:
- Only create PR if:
* Bug count decreases by at least 1
* No new security vulnerabilities introduced
* Code coverage does not decrease
* Technical debt reduces by at least 15 minutes
If changes do not meet these thresholds, explain why and skip PR creation."""
```
{{< /tab >}}
{{< /tabs >}}
### Next steps
Learn how to troubleshoot common issues.
## Troubleshoot code quality workflows
This page covers common issues you might encounter when building code quality
workflows with E2B sandboxes and MCP servers, along with their solutions.
If you're experiencing problems not covered here, check the
[E2B documentation](https://e2b.dev/docs).
### MCP tools not available
Issue: Claude reports `I don't have any MCP tools available`.
Solution:
1. Verify you're using the authorization header:
```plaintext
--header "Authorization: Bearer ${mcpToken}"
```
2. Check you're waiting for MCP initialization.
```typescript
// typescript
await new Promise((resolve) => setTimeout(resolve, 1000));
```
```python
# python
await asyncio.sleep(1)
```
3. Ensure credentials are in both `envs` and `mcp` configuration:
```typescript
// typescript
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
```
```python
# python
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
```
4. Verify your API tokens are valid and have proper scopes.
### GitHub tools work but SonarQube doesn't
Issue: GitHub MCP tools load but SonarQube tools don't appear.
Solution: SonarQube MCP server requires GitHub to be configured simultaneously.
Always include both servers in your sandbox configuration, even if you're only
testing one.
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
// Include both servers even if only using one
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
# Include both servers even if only using one
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
```
{{< /tab >}}
{{< /tabs >}}
### Claude can't access private repositories
Issue: "I don't have access to that repository".
Solution:
1. Verify your GitHub token has `repo` scope (not just `public_repo`).
2. Test with a public repository first.
3. Ensure the repository owner and name are correct in your `.env`:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```plaintext
GITHUB_OWNER=your_github_username
GITHUB_REPO=your_repository_name
```
{{< /tab >}}
{{< tab name="Python" >}}
```plaintext
GITHUB_OWNER=your_github_username
GITHUB_REPO=your_repository_name
```
{{< /tab >}}
{{< /tabs >}}
### Workflow times out or runs too long
Issue: Workflow doesn't complete or Claude credits run out.
Solutions:
1. Use `timeoutMs: 0` (TypeScript) or `timeout_ms=0` (Python) for complex workflows to allow unlimited time:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
await sbx.commands.run(
`echo '${prompt}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0, // No timeout
onStdout: console.log,
onStderr: console.log,
},
);
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout_ms=0, # No timeout
on_stdout=print,
on_stderr=print,
)
```
{{< /tab >}}
{{< /tabs >}}
2. Break complex workflows into smaller, focused tasks.
3. Monitor your Anthropic API credit usage.
4. Add checkpoints in prompts: "After each step, show progress before continuing".
### Sandbox cleanup errors
Issue: Sandboxes aren't being cleaned up properly, leading to resource exhaustion.
Solution: Always use proper error handling with cleanup in the `finally` block:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
async function robustWorkflow() {
let sbx: Sandbox | undefined;
try {
sbx = await Sandbox.betaCreate({
// ... configuration
});
// ... workflow logic
} catch (error) {
console.error("Workflow failed:", error);
process.exit(1);
} finally {
if (sbx) {
console.log("Cleaning up sandbox...");
await sbx.kill();
}
}
}
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
async def robust_workflow():
sbx = None
try:
sbx = await AsyncSandbox.beta_create(
# ... configuration
)
# ... workflow logic
except Exception as error:
print(f"Workflow failed: {error}")
sys.exit(1)
finally:
if sbx:
print("Cleaning up sandbox...")
await sbx.kill()
```
{{< /tab >}}
{{< /tabs >}}
### Environment variable not loading
Issue: Script fails with "undefined" or "None" for environment variables.
Solution:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
1. Ensure `dotenv` is loaded at the top of your file:
```typescript
import "dotenv/config";
```
2. Verify the `.env` file is in the same directory as your script.
3. Check variable names match exactly (case-sensitive):
```typescript
// .env file
GITHUB_TOKEN = ghp_xxxxx;
// In code
process.env.GITHUB_TOKEN; // Correct
process.env.github_token; // Wrong - case doesn't match
```
{{< /tab >}}
{{< tab name="Python" >}}
1. Ensure `dotenv` is loaded at the top of your file:
```python
from dotenv import load_dotenv
load_dotenv()
```
2. Verify the `.env` file is in the same directory as your script.
3. Check variable names match exactly (case-sensitive):
```python
# .env file
GITHUB_TOKEN=ghp_xxxxx
# In code
os.getenv("GITHUB_TOKEN") # Correct
os.getenv("github_token") # Wrong - case doesn't match
```
{{< /tab >}}
{{< /tabs >}}
### SonarQube returns empty results
Issue: SonarQube analysis returns no projects or issues.
Solution:
1. Verify your SonarCloud organization key is correct.
2. Ensure you have at least one project configured in SonarCloud.
3. Check that your SonarQube token has the necessary permissions.
4. Confirm your project has been analyzed at least once in SonarCloud.

View File

@@ -1,334 +0,0 @@
---
title: Troubleshoot code quality workflows
linkTitle: Troubleshoot
summary: Resolve common issues with E2B sandboxes, MCP server connections, and GitHub/SonarQube integration.
description: Solutions for MCP tools not loading, authentication errors, permission issues, workflow timeouts, and other common problems when building code quality workflows with E2B.
keywords: sonarqube, e2b, mcp, troubleshooting, debugging, authentication, code quality
weight: 30
---
This page covers common issues you might encounter when building code quality
workflows with E2B sandboxes and MCP servers, along with their solutions.
If you're experiencing problems not covered here, check the
[E2B documentation](https://e2b.dev/docs).
## MCP tools not available
Issue: Claude reports `I don't have any MCP tools available`.
Solution:
1. Verify you're using the authorization header:
```plaintext
--header "Authorization: Bearer ${mcpToken}"
```
2. Check you're waiting for MCP initialization.
```typescript
// typescript
await new Promise((resolve) => setTimeout(resolve, 1000));
```
```python
# python
await asyncio.sleep(1)
```
3. Ensure credentials are in both `envs` and `mcp` configuration:
```typescript
// typescript
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
```
```python
# python
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
```
4. Verify your API tokens are valid and have proper scopes.
## GitHub tools work but SonarQube doesn't
Issue: GitHub MCP tools load but SonarQube tools don't appear.
Solution: SonarQube MCP server requires GitHub to be configured simultaneously.
Always include both servers in your sandbox configuration, even if you're only
testing one.
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
// Include both servers even if only using one
const sbx = await Sandbox.betaCreate({
envs: {
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
SONARQUBE_TOKEN: process.env.SONARQUBE_TOKEN!,
},
mcp: {
githubOfficial: {
githubPersonalAccessToken: process.env.GITHUB_TOKEN!,
},
sonarqube: {
org: process.env.SONARQUBE_ORG!,
token: process.env.SONARQUBE_TOKEN!,
url: "https://sonarcloud.io",
},
},
});
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
# Include both servers even if only using one
sbx = await AsyncSandbox.beta_create(
envs={
"ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
"GITHUB_TOKEN": os.getenv("GITHUB_TOKEN"),
"SONARQUBE_TOKEN": os.getenv("SONARQUBE_TOKEN"),
},
mcp={
"githubOfficial": {
"githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
},
"sonarqube": {
"org": os.getenv("SONARQUBE_ORG"),
"token": os.getenv("SONARQUBE_TOKEN"),
"url": "https://sonarcloud.io",
},
},
)
```
{{< /tab >}}
{{< /tabs >}}
## Claude can't access private repositories
Issue: "I don't have access to that repository".
Solution:
1. Verify your GitHub token has `repo` scope (not just `public_repo`).
2. Test with a public repository first.
3. Ensure the repository owner and name are correct in your `.env`:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```plaintext
GITHUB_OWNER=your_github_username
GITHUB_REPO=your_repository_name
```
{{< /tab >}}
{{< tab name="Python" >}}
```plaintext
GITHUB_OWNER=your_github_username
GITHUB_REPO=your_repository_name
```
{{< /tab >}}
{{< /tabs >}}
## Workflow times out or runs too long
Issue: Workflow doesn't complete or Claude credits run out.
Solutions:
1. Use `timeoutMs: 0` (TypeScript) or `timeout_ms=0` (Python) for complex workflows to allow unlimited time:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
await sbx.commands.run(
`echo '${prompt}' | claude -p --dangerously-skip-permissions`,
{
timeoutMs: 0, // No timeout
onStdout: console.log,
onStderr: console.log,
},
);
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
await sbx.commands.run(
f"echo '{prompt}' | claude -p --dangerously-skip-permissions",
timeout_ms=0, # No timeout
on_stdout=print,
on_stderr=print,
)
```
{{< /tab >}}
{{< /tabs >}}
2. Break complex workflows into smaller, focused tasks.
3. Monitor your Anthropic API credit usage.
4. Add checkpoints in prompts: "After each step, show progress before continuing".
## Sandbox cleanup errors
Issue: Sandboxes aren't being cleaned up properly, leading to resource exhaustion.
Solution: Always use proper error handling with cleanup in the `finally` block:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
```typescript
async function robustWorkflow() {
let sbx: Sandbox | undefined;
try {
sbx = await Sandbox.betaCreate({
// ... configuration
});
// ... workflow logic
} catch (error) {
console.error("Workflow failed:", error);
process.exit(1);
} finally {
if (sbx) {
console.log("Cleaning up sandbox...");
await sbx.kill();
}
}
}
```
{{< /tab >}}
{{< tab name="Python" >}}
```python
async def robust_workflow():
sbx = None
try:
sbx = await AsyncSandbox.beta_create(
# ... configuration
)
# ... workflow logic
except Exception as error:
print(f"Workflow failed: {error}")
sys.exit(1)
finally:
if sbx:
print("Cleaning up sandbox...")
await sbx.kill()
```
{{< /tab >}}
{{< /tabs >}}
## Environment variable not loading
Issue: Script fails with "undefined" or "None" for environment variables.
Solution:
{{< tabs group="language" >}}
{{< tab name="TypeScript" >}}
1. Ensure `dotenv` is loaded at the top of your file:
```typescript
import "dotenv/config";
```
2. Verify the `.env` file is in the same directory as your script.
3. Check variable names match exactly (case-sensitive):
```typescript
// .env file
GITHUB_TOKEN = ghp_xxxxx;
// In code
process.env.GITHUB_TOKEN; // Correct
process.env.github_token; // Wrong - case doesn't match
```
{{< /tab >}}
{{< tab name="Python" >}}
1. Ensure `dotenv` is loaded at the top of your file:
```python
from dotenv import load_dotenv
load_dotenv()
```
2. Verify the `.env` file is in the same directory as your script.
3. Check variable names match exactly (case-sensitive):
```python
# .env file
GITHUB_TOKEN=ghp_xxxxx
# In code
os.getenv("GITHUB_TOKEN") # Correct
os.getenv("github_token") # Wrong - case doesn't match
```
{{< /tab >}}
{{< /tabs >}}
## SonarQube returns empty results
Issue: SonarQube analysis returns no projects or issues.
Solution:
1. Verify your SonarCloud organization key is correct.
2. Ensure you have at least one project configured in SonarCloud.
3. Check that your SonarQube token has the necessary permissions.
4. Confirm your project has been analyzed at least once in SonarCloud.

View File

@@ -1,40 +0,0 @@
---
description: Containerize a Golang application and monitor it with Prometheus and Grafana.
keywords: golang, prometheus, grafana, monitoring, containerize
title: Monitor a Golang application with Prometheus and Grafana
summary: |
Learn how to containerize a Golang application and monitor it with Prometheus and Grafana.
linkTitle: Prometheus and Grafana
languages: [go]
params:
time: 45 minutes
---
The guide teaches you how to containerize a Golang application and monitor it with Prometheus and Grafana.
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
## Overview
To make sure your application is working as intended, monitoring is important. One of the most popular monitoring tools is Prometheus. Prometheus is an open-source monitoring and alerting toolkit that is designed for reliability and scalability. It collects metrics from monitored targets by scraping metrics HTTP endpoints on these targets. To visualize the metrics, you can use Grafana. Grafana is an open-source platform for monitoring and observability that allows you to query, visualize, alert on, and understand your metrics no matter where they are stored.
In this guide, you will be creating a Golang server with some endpoints to simulate a real-world application. Then you will expose metrics from the server using Prometheus. Finally, you will visualize the metrics using Grafana. You will containerize the Golang application, and using the Docker Compose file, you will connect all the services: Golang, Prometheus, and Grafana.
## What will you learn?
* Create a Golang application with custom Prometheus metrics.
* Containerize a Golang application.
* Use Docker Compose to run multiple services and connect them together to monitor a Golang application with Prometheus and Grafana.
* Visualize the metrics using Grafana dashboards.
## Prerequisites
- A good understanding of Golang is assumed.
- You must me familiar with Prometheus and creating dashboards in Grafana.
- You must have familiarity with Docker concepts like containers, images, and Dockerfiles. If you are new to Docker, you can start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
## Next steps
You will create a Golang server and expose metrics using Prometheus.

View File

@@ -1,250 +0,0 @@
---
title: Building the application
linkTitle: Understand the application
weight: 10 #
keywords: go, golang, prometheus, grafana, containerize, monitor
description: Learn how to create a Golang server to register metrics with Prometheus.
---
## Prerequisites
* You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
You will be creating a Golang server with some endpoints to simulate a real-world application. Then you will expose metrics from the server using Prometheus.
## Getting the sample application
Clone the sample application to use with this guide. Open a terminal, change
directory to a directory that you want to work in, and run the following
command to clone the repository:
```console
$ git clone https://github.com/dockersamples/go-prometheus-monitoring.git
```
Once you cloned you will see the following content structure inside `go-prometheus-monitoring` directory,
```text
go-prometheus-monitoring
├── CONTRIBUTING.md
├── Docker
│ ├── grafana.yml
│ └── prometheus.yml
├── dashboard.json
├── Dockerfile
├── LICENSE
├── README.md
├── compose.yaml
├── go.mod
├── go.sum
└── main.go
```
- **main.go** - The entry point of the application.
- **go.mod and go.sum** - Go module files.
- **Dockerfile** - Dockerfile used to build the app.
- **Docker/** - Contains the Docker Compose configuration files for Grafana and Prometheus.
- **compose.yaml** - Compose file to launch everything (Golang app, Prometheus, and Grafana).
- **dashboard.json** - Grafana dashboard configuration file.
- **Dockerfile** - Dockerfile used to build the Golang app.
- **compose.yaml** - Docker Compose file to launch everything (Golang app, Prometheus, and Grafana).
- Other files are for licensing and documentation purposes.
## Understanding the application
The following is the complete logic of the application you will find in `main.go`.
```go
package main
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Define metrics
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Total number of requests processed by the API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Total number of errors returned by the API",
}, []string{"path", "status"})
)
// Custom registry (without default Go metrics)
var customRegistry = prometheus.NewRegistry()
// Register metrics with custom registry
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
func main() {
router := gin.Default()
// Register /metrics before middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
// Custom metrics handler with custom registry
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware to record incoming requests metrics
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
```
In this part of the code, you have imported the required packages `gin`, `prometheus`, and `promhttp`. Then you have defined a couple of variables, `HttpRequestTotal` and `HttpRequestErrorTotal` are Prometheus counter metrics, and `customRegistry` is a custom registry that will be used to register these metrics. The name of the metric is a string that you can use to identify the metric. The help string is a string that will be shown when you query the `/metrics` endpoint to understand the metric. The reason you are using the custom registry is so avoid the default Go metrics that are registered by default by the Prometheus client. Then using the `init` function you are registering the metrics with the custom registry.
```go
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Define metrics
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Total number of requests processed by the API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Total number of errors returned by the API",
}, []string{"path", "status"})
)
// Custom registry (without default Go metrics)
var customRegistry = prometheus.NewRegistry()
// Register metrics with custom registry
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
```
In the `main` function, you have created a new instance of the `gin` framework and created three routes. You can see the health endpoint that is on path `/health` that will return a JSON with `{"message": "Up and running!"}` and the `/v1/users` endpoint that will return a JSON with `{"message": "Hello from /v1/users"}`. The third route is for the `/metrics` endpoint that will return the metrics in the Prometheus format. Then you have `RequestMetricsMiddleware` middleware, it will be called for every request made to the API. It will record the incoming requests metrics like status codes and paths. Finally, you are running the gin application on port 8000.
```golang
func main() {
router := gin.Default()
// Register /metrics before middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
```
Now comes the middleware function `RequestMetricsMiddleware`. This function is called for every request made to the API. It increments the `HttpRequestTotal` counter (different counter for different paths and status codes) if the status code is less than or equal to 400. If the status code is greater than 400, it increments the `HttpRequestErrorTotal` counter (different counter for different paths and status codes). The `PrometheusHandler` function is the custom handler that will be called for the `/metrics` endpoint. It will return the metrics in the Prometheus format.
```golang
// Custom metrics handler with custom registry
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware to record incoming requests metrics
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
```
That's it, this was the complete gist of the application. Now it's time to run and test if the app is registering metrics correctly.
## Running the application
Make sure you are still inside `go-prometheus-monitoring` directory in the terminal, and run the following command. Install the dependencies by running `go mod tidy` and then build and run the application by running `go run main.go`. Then visit `http://localhost:8000/health` or `http://localhost:8000/v1/users`. You should see the output `{"message": "Up and running!"}` or `{"message": "Hello from /v1/users"}`. If you are able to see this then your app is successfully up and running.
Now, check your application's metrics by accessing the `/metrics` endpoint.
Open `http://localhost:8000/metrics` in your browser. You should see similar output to the following.
```sh
# HELP api_http_request_error_total Total number of errors returned by the API
# TYPE api_http_request_error_total counter
api_http_request_error_total{path="/",status="404"} 1
api_http_request_error_total{path="//v1/users",status="404"} 1
api_http_request_error_total{path="/favicon.ico",status="404"} 1
# HELP api_http_request_total Total number of requests processed by the API
# TYPE api_http_request_total counter
api_http_request_total{path="/health",status="200"} 2
api_http_request_total{path="/v1/users",status="200"} 1
```
In the terminal, press `ctrl` + `c` to stop the application.
> [!Note]
> If you don't want to run the application locally, and want to run it in a Docker container, skip to next page where you create a Dockerfile and containerize the application.
## Summary
In this section, you learned how to create a Golang app to register metrics with Prometheus. By implementing middleware functions, you were able to increment the counters based on the request path and status codes.
## Next steps
In the next section, you'll learn how to containerize your application.

View File

@@ -1,166 +0,0 @@
---
title: Connecting services with Docker Compose
linkTitle: Connect with Compose
weight: 30 #
keywords: go, golang, prometheus, grafana, containerize, monitor
description: Learn how to connect services with Docker Compose to monitor a Golang application with Prometheus and Grafana.
---
Now that you have containerized the Golang application, you will use Docker Compose to connect your services together. You will connect the Golang application, Prometheus, and Grafana services together to monitor the Golang application with Prometheus and Grafana.
## Creating a Docker Compose file
Create a new file named `compose.yml` in the root directory of your Golang application. The Docker Compose file contains instructions to run multiple services and connect them together.
Here is a Docker Compose file for a project that uses Golang, Prometheus, and Grafana. You will also find this file in the `go-prometheus-monitoring` directory.
```yaml
services:
api:
container_name: go-api
build:
context: .
dockerfile: Dockerfile
image: go-api:latest
ports:
- 8000:8000
networks:
- go-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 5
develop:
watch:
- path: .
action: rebuild
prometheus:
container_name: prometheus
image: prom/prometheus:v2.55.0
volumes:
- ./Docker/prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- 9090:9090
networks:
- go-network
grafana:
container_name: grafana
image: grafana/grafana:11.3.0
volumes:
- ./Docker/grafana.yml:/etc/grafana/provisioning/datasources/datasource.yaml
- grafana-data:/var/lib/grafana
ports:
- 3000:3000
networks:
- go-network
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=password
volumes:
grafana-data:
networks:
go-network:
driver: bridge
```
## Understanding the Docker Compose file
The Docker Compose file consists of three services:
- **Golang application service**: This service builds the Golang application using the Dockerfile and runs it in a container. It exposes the application's port `8000` and connects to the `go-network` network. It also defines a health check to monitor the application's health. You have also used `healthcheck` to monitor the health of the application. The health check runs every 30 seconds and retries 5 times if the health check fails. The health check uses the `curl` command to check the `/health` endpoint of the application. Apart from the health check, you have also added a `develop` section to watch the changes in the application's source code and rebuild the application using the Docker Compose Watch feature.
- **Prometheus service**: This service runs the Prometheus server in a container. It uses the official Prometheus image `prom/prometheus:v2.55.0`. It exposes the Prometheus server on port `9090` and connects to the `go-network` network. You have also mounted the `prometheus.yml` file from the `Docker` directory which is present in the root directory of your project. The `prometheus.yml` file contains the Prometheus configuration to scrape the metrics from the Golang application. This is how you connect the Prometheus server to the Golang application.
```yaml
global:
scrape_interval: 10s
evaluation_interval: 10s
scrape_configs:
- job_name: myapp
static_configs:
- targets: ["api:8000"]
```
In the `prometheus.yml` file, you have defined a job named `myapp` to scrape the metrics from the Golang application. The `targets` field specifies the target to scrape the metrics from. In this case, the target is the Golang application running on port `8000`. The `api` is the service name of the Golang application in the Docker Compose file. The Prometheus server will scrape the metrics from the Golang application every 10 seconds.
- **Grafana service**: This service runs the Grafana server in a container. It uses the official Grafana image `grafana/grafana:11.3.0`. It exposes the Grafana server on port `3000` and connects to the `go-network` network. You have also mounted the `grafana.yml` file from the `Docker` directory which is present in the root directory of your project. The `grafana.yml` file contains the Grafana configuration to add the Prometheus data source. This is how you connect the Grafana server to the Prometheus server. In the environment variables, you have set the Grafana admin user and password, which will be used to log in to the Grafana dashboard.
```yaml
apiVersion: 1
datasources:
- name: Prometheus (Main)
type: prometheus
url: http://prometheus:9090
isDefault: true
```
In the `grafana.yml` file, you have defined a Prometheus data source named `Prometheus (Main)`. The `type` field specifies the type of the data source, which is `prometheus`. The `url` field specifies the URL of the Prometheus server to fetch the metrics from. In this case, the URL is `http://prometheus:9090`. `prometheus` is the service name of the Prometheus server in the Docker Compose file. The `isDefault` field specifies whether the data source is the default data source in Grafana.
Apart from the services, the Docker Compose file also defines a volume named `grafana-data` to persist the Grafana data and a network named `go-network` to connect the services together. You have created a custom network `go-network` to connect the services together. The `driver: bridge` field specifies the network driver to use for the network.
## Building and running the services
Now that you have the Docker Compose file, you can build the services and run them together using Docker Compose.
To build and run the services, run the following command in the terminal:
```console
$ docker compose up
```
The `docker compose up` command builds the services defined in the Docker Compose file and runs them together. You will see the similar output in the terminal:
```console
✔ Network go-prometheus-monitoring_go-network Created 0.0s
✔ Container grafana Created 0.3s
✔ Container go-api Created 0.2s
✔ Container prometheus Created 0.3s
Attaching to go-api, grafana, prometheus
go-api | [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
go-api |
go-api | [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
go-api | - using env: export GIN_MODE=release
go-api | - using code: gin.SetMode(gin.ReleaseMode)
go-api |
go-api | [GIN-debug] GET /metrics --> main.PrometheusHandler.func1 (3 handlers)
go-api | [GIN-debug] GET /health --> main.main.func1 (4 handlers)
go-api | [GIN-debug] GET /v1/users --> main.main.func2 (4 handlers)
go-api | [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
go-api | Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
go-api | [GIN-debug] Listening and serving HTTP on :8000
prometheus | ts=2025-03-15T05:57:06.676Z caller=main.go:627 level=info msg="No time or size retention was set so using the default time retention" duration=15d
prometheus | ts=2025-03-15T05:57:06.678Z caller=main.go:671 level=info msg="Starting Prometheus Server" mode=server version="(version=2.55.0, branch=HEAD, revision=91d80252c3e528728b0f88d254dd720f6be07cb8)"
grafana | logger=settings t=2025-03-15T05:57:06.865335506Z level=info msg="Config overridden from command line" arg="default.log.mode=console"
grafana | logger=settings t=2025-03-15T05:57:06.865337131Z level=info msg="Config overridden from Environment variable" var="GF_PATHS_DATA=/var/lib/grafana"
grafana | logger=ngalert.state.manager t=2025-03-15T05:57:07.088956839Z level=info msg="State
.
.
grafana | logger=plugin.angulardetectorsprovider.dynamic t=2025-03-15T05:57:07.530317298Z level=info msg="Patterns update finished" duration=440.489125ms
```
The services will start running, and you can access the Golang application at `http://localhost:8000`, Prometheus at `http://localhost:9090/health`, and Grafana at `http://localhost:3000`. You can also check the running containers using the `docker ps` command.
```console
$ docker ps
```
## Summary
In this section, you learned how to connect services together using Docker Compose. You created a Docker Compose file to run multiple services together and connect them using networks. You also learned how to build and run the services using Docker Compose.
Related information:
- [Docker Compose overview](/manuals/compose/_index.md)
- [Compose file reference](/reference/compose-file/_index.md)
Next, you will learn how to develop the Golang application with Docker Compose and monitor it with Prometheus and Grafana.
## Next steps
In the next section, you will learn how to develop the Golang application with Docker. You will also learn how to use Docker Compose Watch to rebuild the image whenever you make changes to the code. Lastly, you will test the application and visualize the metrics in Grafana using Prometheus as the data source.

View File

@@ -1,103 +0,0 @@
---
title: Containerize a Golang application
linkTitle: Containerize your app
weight: 20
keywords: go, golang, containerize, initialize
description: Learn how to containerize a Golang application.
---
Containerization helps you bundle the application and its dependencies into a single package called a container. This package can run on any platform without worrying about the environment. In this section, you will learn how to containerize a Golang application using Docker.
To containerize a Golang application, you first need to create a Dockerfile. The Dockerfile contains instructions to build and run the application in a container. Also, when creating a Dockerfile, you can follow different sets of best practices to optimize the image size and make it more secure.
## Creating a Dockerfile
Create a new file named `Dockerfile` in the root directory of your Golang application. The Dockerfile contains instructions to build and run the application in a container.
The following is a Dockerfile for a Golang application. You will also find this file in the `go-prometheus-monitoring` directory.
```dockerfile
# Use the official Golang image as the base
FROM golang:1.24-alpine AS builder
# Set environment variables
ENV CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
# Set working directory inside the container
WORKDIR /build
# Copy go.mod and go.sum files for dependency installation
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the entire application source
COPY . .
# Build the Go binary
RUN go build -o /app .
# Final lightweight stage
FROM alpine:3.21 AS final
# Copy the compiled binary from the builder stage
COPY --from=builder /app /bin/app
# Expose the application's port
EXPOSE 8000
# Run the application
CMD ["bin/app"]
```
## Understanding the Dockerfile
The Dockerfile consists of two stages:
1. **Build stage**: This stage uses the official Golang image as the base and sets the necessary environment variables. It also sets the working directory inside the container, copies the `go.mod` and `go.sum` files for dependency installation, downloads the dependencies, copies the entire application source, and builds the Go binary.
You use the `golang:1.24-alpine` image as the base image for the build stage. The `CGO_ENABLED=0` environment variable disables CGO, which is useful for building static binaries. You also set the `GOOS` and `GOARCH` environment variables to `linux` and `amd64`, respectively, to build the binary for the Linux platform.
2. **Final stage**: This stage uses the official Alpine image as the base and copies the compiled binary from the build stage. It also exposes the application's port and runs the application.
You use the `alpine:3.21` image as the base image for the final stage. You copy the compiled binary from the build stage to the final image. You expose the application's port using the `EXPOSE` instruction and run the application using the `CMD` instruction.
Apart from the multi-stage build, the Dockerfile also follows best practices such as using the official images, setting the working directory, and copying only the necessary files to the final image. You can further optimize the Dockerfile by other best practices.
## Build the Docker image and run the application
One you have the Dockerfile, you can build the Docker image and run the application in a container.
To build the Docker image, run the following command in the terminal:
```console
$ docker build -t go-api:latest .
```
After building the image, you can run the application in a container using the following command:
```console
$ docker run -p 8000:8000 go-api:latest
```
The application will start running inside the container, and you can access it at `http://localhost:8000`. You can also check the running containers using the `docker ps` command.
```console
$ docker ps
```
## Summary
In this section, you learned how to containerize a Golang application using a Dockerfile. You created a multi-stage Dockerfile to build and run the application in a container. You also learned about best practices to optimize the Docker image size and make it more secure.
Related information:
- [Dockerfile reference](/reference/dockerfile.md)
- [.dockerignore file](/reference/dockerfile.md#dockerignore-file)
## Next steps
In the next section, you will learn how to use Docker Compose to connect and run multiple services together to monitor a Golang application with Prometheus and Grafana.

View File

@@ -1,84 +0,0 @@
---
title: Developing your application
linkTitle: Develop your app
weight: 40
keywords: go, golang, containerize, initialize
description: Learn how to develop the Golang application with Docker.
---
In the last section, you saw how using Docker Compose, you can connect your services together. In this section, you will learn how to develop the Golang application with Docker. You will also see how to use Docker Compose Watch to rebuild the image whenever you make changes to the code. Lastly, you will test the application and visualize the metrics in Grafana using Prometheus as the data source.
## Developing the application
Now, if you make any changes to your Golang application locally, it needs to reflect in the container, right? To do that, one approach is use the `--build` flag in Docker Compose after making changes in the code. This will rebuild all the services which have the `build` instruction in the `compose.yml` file, in your case, the `api` service (Golang application).
```console
docker compose up --build
```
But, this is not the best approach. This is not efficient. Every time you make a change in the code, you need to rebuild manually. This is not is not a good flow for development.
The better approach is to use Docker Compose Watch. In the `compose.yml` file, under the service `api`, you have added the `develop` section. So, it's more like a hot reloading. Whenever you make changes to code (defined in `path`), it will rebuild the image (or restart depending on the action). This is how you can use it:
```yaml {hl_lines="17-20",linenos=true}
services:
api:
container_name: go-api
build:
context: .
dockerfile: Dockerfile
image: go-api:latest
ports:
- 8000:8000
networks:
- go-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 5
develop:
watch:
- path: .
action: rebuild
```
Once you have added the `develop` section in the `compose.yml` file, you can use the following command to start the development server:
```console
$ docker compose watch
```
Now, if you modify your `main.go` or any other file in the project, the `api` service will be rebuilt automatically. You will see the following output in the terminal:
```bash
Rebuilding service(s) ["api"] after changes were detected...
[+] Building 8.1s (15/15) FINISHED docker:desktop-linux
=> [api internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 704B 0.0s
=> [api internal] load metadata for docker.io/library/alpine:3.17 1.1s
.
=> => exporting manifest list sha256:89ebc86fd51e27c1da440dc20858ff55fe42211a1930c2d51bbdce09f430c7f1 0.0s
=> => naming to docker.io/library/go-api:latest 0.0s
=> => unpacking to docker.io/library/go-api:latest 0.0s
=> [api] resolving provenance for metadata file 0.0s
service(s) ["api"] successfully built
```
## Testing the application
Now that you have your application running, head over to the Grafana dashboard to visualize the metrics you are registering. Open your browser and navigate to `http://localhost:3000`. You will be greeted with the Grafana login page. The login credentials are the ones provided in Compose file.
Once you are logged in, you can create a new dashboard. While creating dashboard you will notice that is default data source is `Prometheus`. This is because you have already configured the data source in the `grafana.yml` file.
![The optional settings screen with the options specified.](../images/grafana-dash.png)
You can use different panels to visualize the metrics. This guide doesn't go into details of Grafana. You can refer to the [Grafana documentation](https://grafana.com/docs/grafana/latest/) for more information. There is a Bar Gauge panel to visualize the total number of requests from different endpoints. You used the `api_http_request_total` and `api_http_request_error_total` metrics to get the data.
![The optional settings screen with the options specified.](../images/grafana-panel.png)
You created this panel to visualize the total number of requests from different endpoints to compare the successful and failed requests. For all the good requests, the bar will be green, and for all the failed requests, the bar will be red. Plus it will also show the from which endpoint the request is coming, either it's a successful request or a failed request. If you want to use this panel, you can import the `dashboard.json` file from the repository you cloned.
## Summary
You've come to the end of this guide. You learned how to develop the Golang application with Docker. You also saw how to use Docker Compose Watch to rebuild the image whenever you make changes to the code. Lastly, you tested the application and visualized the metrics in Grafana using Prometheus as the data source.

View File

@@ -0,0 +1,629 @@
---
description: Containerize a Golang application and monitor it with Prometheus and Grafana.
keywords: golang, prometheus, grafana, monitoring, containerize
title: Monitor a Golang application with Prometheus and Grafana
summary: |
Learn how to containerize a Golang application and monitor it with Prometheus and Grafana.
linkTitle: Prometheus and Grafana
aliases:
- /guides/go-prometheus-monitoring/application/
- /guides/go-prometheus-monitoring/compose/
- /guides/go-prometheus-monitoring/containerize/
- /guides/go-prometheus-monitoring/develop/
params:
tags: [cicd]
time: 45 minutes
---
The guide teaches you how to containerize a Golang application and monitor it with Prometheus and Grafana.
> **Acknowledgment**
>
> Docker would like to thank [Pradumna Saraf](https://twitter.com/pradumna_saraf) for his contribution to this guide.
## Overview
To make sure your application is working as intended, monitoring is important. One of the most popular monitoring tools is Prometheus. Prometheus is an open-source monitoring and alerting toolkit that is designed for reliability and scalability. It collects metrics from monitored targets by scraping metrics HTTP endpoints on these targets. To visualize the metrics, you can use Grafana. Grafana is an open-source platform for monitoring and observability that allows you to query, visualize, alert on, and understand your metrics no matter where they are stored.
In this guide, you will be creating a Golang server with some endpoints to simulate a real-world application. Then you will expose metrics from the server using Prometheus. Finally, you will visualize the metrics using Grafana. You will containerize the Golang application, and using the Docker Compose file, you will connect all the services: Golang, Prometheus, and Grafana.
## What will you learn?
* Create a Golang application with custom Prometheus metrics.
* Containerize a Golang application.
* Use Docker Compose to run multiple services and connect them together to monitor a Golang application with Prometheus and Grafana.
* Visualize the metrics using Grafana dashboards.
## Prerequisites
- A good understanding of Golang is assumed.
- You must me familiar with Prometheus and creating dashboards in Grafana.
- You must have familiarity with Docker concepts like containers, images, and Dockerfiles. If you are new to Docker, you can start with the [Docker basics](/get-started/docker-concepts/the-basics/what-is-a-container.md) guide.
## Next steps
You will create a Golang server and expose metrics using Prometheus.
## Building the application
### Prerequisites
* You have a [Git client](https://git-scm.com/downloads). The examples in this section use a command-line based Git client, but you can use any client.
You will be creating a Golang server with some endpoints to simulate a real-world application. Then you will expose metrics from the server using Prometheus.
### Getting the sample application
Clone the sample application to use with this guide. Open a terminal, change
directory to a directory that you want to work in, and run the following
command to clone the repository:
```console
$ git clone https://github.com/dockersamples/go-prometheus-monitoring.git
```
Once you cloned you will see the following content structure inside `go-prometheus-monitoring` directory,
```text
go-prometheus-monitoring
├── CONTRIBUTING.md
├── Docker
│ ├── grafana.yml
│ └── prometheus.yml
├── dashboard.json
├── Dockerfile
├── LICENSE
├── README.md
├── compose.yaml
├── go.mod
├── go.sum
└── main.go
```
- **main.go** - The entry point of the application.
- **go.mod and go.sum** - Go module files.
- **Dockerfile** - Dockerfile used to build the app.
- **Docker/** - Contains the Docker Compose configuration files for Grafana and Prometheus.
- **compose.yaml** - Compose file to launch everything (Golang app, Prometheus, and Grafana).
- **dashboard.json** - Grafana dashboard configuration file.
- **Dockerfile** - Dockerfile used to build the Golang app.
- **compose.yaml** - Docker Compose file to launch everything (Golang app, Prometheus, and Grafana).
- Other files are for licensing and documentation purposes.
### Understanding the application
The following is the complete logic of the application you will find in `main.go`.
```go
package main
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Define metrics
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Total number of requests processed by the API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Total number of errors returned by the API",
}, []string{"path", "status"})
)
// Custom registry (without default Go metrics)
var customRegistry = prometheus.NewRegistry()
// Register metrics with custom registry
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
func main() {
router := gin.Default()
// Register /metrics before middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
// Custom metrics handler with custom registry
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware to record incoming requests metrics
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
```
In this part of the code, you have imported the required packages `gin`, `prometheus`, and `promhttp`. Then you have defined a couple of variables, `HttpRequestTotal` and `HttpRequestErrorTotal` are Prometheus counter metrics, and `customRegistry` is a custom registry that will be used to register these metrics. The name of the metric is a string that you can use to identify the metric. The help string is a string that will be shown when you query the `/metrics` endpoint to understand the metric. The reason you are using the custom registry is so avoid the default Go metrics that are registered by default by the Prometheus client. Then using the `init` function you are registering the metrics with the custom registry.
```go
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Define metrics
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Total number of requests processed by the API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Total number of errors returned by the API",
}, []string{"path", "status"})
)
// Custom registry (without default Go metrics)
var customRegistry = prometheus.NewRegistry()
// Register metrics with custom registry
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
```
In the `main` function, you have created a new instance of the `gin` framework and created three routes. You can see the health endpoint that is on path `/health` that will return a JSON with `{"message": "Up and running!"}` and the `/v1/users` endpoint that will return a JSON with `{"message": "Hello from /v1/users"}`. The third route is for the `/metrics` endpoint that will return the metrics in the Prometheus format. Then you have `RequestMetricsMiddleware` middleware, it will be called for every request made to the API. It will record the incoming requests metrics like status codes and paths. Finally, you are running the gin application on port 8000.
```golang
func main() {
router := gin.Default()
// Register /metrics before middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
```
Now comes the middleware function `RequestMetricsMiddleware`. This function is called for every request made to the API. It increments the `HttpRequestTotal` counter (different counter for different paths and status codes) if the status code is less than or equal to 400. If the status code is greater than 400, it increments the `HttpRequestErrorTotal` counter (different counter for different paths and status codes). The `PrometheusHandler` function is the custom handler that will be called for the `/metrics` endpoint. It will return the metrics in the Prometheus format.
```golang
// Custom metrics handler with custom registry
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware to record incoming requests metrics
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
```
That's it, this was the complete gist of the application. Now it's time to run and test if the app is registering metrics correctly.
### Running the application
Make sure you are still inside `go-prometheus-monitoring` directory in the terminal, and run the following command. Install the dependencies by running `go mod tidy` and then build and run the application by running `go run main.go`. Then visit `http://localhost:8000/health` or `http://localhost:8000/v1/users`. You should see the output `{"message": "Up and running!"}` or `{"message": "Hello from /v1/users"}`. If you are able to see this then your app is successfully up and running.
Now, check your application's metrics by accessing the `/metrics` endpoint.
Open `http://localhost:8000/metrics` in your browser. You should see similar output to the following.
```sh
# HELP api_http_request_error_total Total number of errors returned by the API
# TYPE api_http_request_error_total counter
api_http_request_error_total{path="/",status="404"} 1
api_http_request_error_total{path="//v1/users",status="404"} 1
api_http_request_error_total{path="/favicon.ico",status="404"} 1
# HELP api_http_request_total Total number of requests processed by the API
# TYPE api_http_request_total counter
api_http_request_total{path="/health",status="200"} 2
api_http_request_total{path="/v1/users",status="200"} 1
```
In the terminal, press `ctrl` + `c` to stop the application.
> [!Note]
> If you don't want to run the application locally, and want to run it in a Docker container, skip to next page where you create a Dockerfile and containerize the application.
### Summary
In this section, you learned how to create a Golang app to register metrics with Prometheus. By implementing middleware functions, you were able to increment the counters based on the request path and status codes.
### Next steps
In the next section, you'll learn how to containerize your application.
## Containerize a Golang application
Containerization helps you bundle the application and its dependencies into a single package called a container. This package can run on any platform without worrying about the environment. In this section, you will learn how to containerize a Golang application using Docker.
To containerize a Golang application, you first need to create a Dockerfile. The Dockerfile contains instructions to build and run the application in a container. Also, when creating a Dockerfile, you can follow different sets of best practices to optimize the image size and make it more secure.
### Creating a Dockerfile
Create a new file named `Dockerfile` in the root directory of your Golang application. The Dockerfile contains instructions to build and run the application in a container.
The following is a Dockerfile for a Golang application. You will also find this file in the `go-prometheus-monitoring` directory.
```dockerfile
# Use the official Golang image as the base
FROM golang:1.24-alpine AS builder
# Set environment variables
ENV CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
# Set working directory inside the container
WORKDIR /build
# Copy go.mod and go.sum files for dependency installation
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the entire application source
COPY . .
# Build the Go binary
RUN go build -o /app .
# Final lightweight stage
FROM alpine:3.21 AS final
# Copy the compiled binary from the builder stage
COPY --from=builder /app /bin/app
# Expose the application's port
EXPOSE 8000
# Run the application
CMD ["bin/app"]
```
### Understanding the Dockerfile
The Dockerfile consists of two stages:
1. **Build stage**: This stage uses the official Golang image as the base and sets the necessary environment variables. It also sets the working directory inside the container, copies the `go.mod` and `go.sum` files for dependency installation, downloads the dependencies, copies the entire application source, and builds the Go binary.
You use the `golang:1.24-alpine` image as the base image for the build stage. The `CGO_ENABLED=0` environment variable disables CGO, which is useful for building static binaries. You also set the `GOOS` and `GOARCH` environment variables to `linux` and `amd64`, respectively, to build the binary for the Linux platform.
2. **Final stage**: This stage uses the official Alpine image as the base and copies the compiled binary from the build stage. It also exposes the application's port and runs the application.
You use the `alpine:3.21` image as the base image for the final stage. You copy the compiled binary from the build stage to the final image. You expose the application's port using the `EXPOSE` instruction and run the application using the `CMD` instruction.
Apart from the multi-stage build, the Dockerfile also follows best practices such as using the official images, setting the working directory, and copying only the necessary files to the final image. You can further optimize the Dockerfile by other best practices.
### Build the Docker image and run the application
One you have the Dockerfile, you can build the Docker image and run the application in a container.
To build the Docker image, run the following command in the terminal:
```console
$ docker build -t go-api:latest .
```
After building the image, you can run the application in a container using the following command:
```console
$ docker run -p 8000:8000 go-api:latest
```
The application will start running inside the container, and you can access it at `http://localhost:8000`. You can also check the running containers using the `docker ps` command.
```console
$ docker ps
```
### Summary
In this section, you learned how to containerize a Golang application using a Dockerfile. You created a multi-stage Dockerfile to build and run the application in a container. You also learned about best practices to optimize the Docker image size and make it more secure.
Related information:
- [Dockerfile reference](/reference/dockerfile.md)
- [.dockerignore file](/reference/dockerfile.md#dockerignore-file)
### Next steps
In the next section, you will learn how to use Docker Compose to connect and run multiple services together to monitor a Golang application with Prometheus and Grafana.
## Connecting services with Docker Compose
Now that you have containerized the Golang application, you will use Docker Compose to connect your services together. You will connect the Golang application, Prometheus, and Grafana services together to monitor the Golang application with Prometheus and Grafana.
### Creating a Docker Compose file
Create a new file named `compose.yml` in the root directory of your Golang application. The Docker Compose file contains instructions to run multiple services and connect them together.
Here is a Docker Compose file for a project that uses Golang, Prometheus, and Grafana. You will also find this file in the `go-prometheus-monitoring` directory.
```yaml
services:
api:
container_name: go-api
build:
context: .
dockerfile: Dockerfile
image: go-api:latest
ports:
- 8000:8000
networks:
- go-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 5
develop:
watch:
- path: .
action: rebuild
prometheus:
container_name: prometheus
image: prom/prometheus:v2.55.0
volumes:
- ./Docker/prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- 9090:9090
networks:
- go-network
grafana:
container_name: grafana
image: grafana/grafana:11.3.0
volumes:
- ./Docker/grafana.yml:/etc/grafana/provisioning/datasources/datasource.yaml
- grafana-data:/var/lib/grafana
ports:
- 3000:3000
networks:
- go-network
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=password
volumes:
grafana-data:
networks:
go-network:
driver: bridge
```
### Understanding the Docker Compose file
The Docker Compose file consists of three services:
- **Golang application service**: This service builds the Golang application using the Dockerfile and runs it in a container. It exposes the application's port `8000` and connects to the `go-network` network. It also defines a health check to monitor the application's health. You have also used `healthcheck` to monitor the health of the application. The health check runs every 30 seconds and retries 5 times if the health check fails. The health check uses the `curl` command to check the `/health` endpoint of the application. Apart from the health check, you have also added a `develop` section to watch the changes in the application's source code and rebuild the application using the Docker Compose Watch feature.
- **Prometheus service**: This service runs the Prometheus server in a container. It uses the official Prometheus image `prom/prometheus:v2.55.0`. It exposes the Prometheus server on port `9090` and connects to the `go-network` network. You have also mounted the `prometheus.yml` file from the `Docker` directory which is present in the root directory of your project. The `prometheus.yml` file contains the Prometheus configuration to scrape the metrics from the Golang application. This is how you connect the Prometheus server to the Golang application.
```yaml
global:
scrape_interval: 10s
evaluation_interval: 10s
scrape_configs:
- job_name: myapp
static_configs:
- targets: ["api:8000"]
```
In the `prometheus.yml` file, you have defined a job named `myapp` to scrape the metrics from the Golang application. The `targets` field specifies the target to scrape the metrics from. In this case, the target is the Golang application running on port `8000`. The `api` is the service name of the Golang application in the Docker Compose file. The Prometheus server will scrape the metrics from the Golang application every 10 seconds.
- **Grafana service**: This service runs the Grafana server in a container. It uses the official Grafana image `grafana/grafana:11.3.0`. It exposes the Grafana server on port `3000` and connects to the `go-network` network. You have also mounted the `grafana.yml` file from the `Docker` directory which is present in the root directory of your project. The `grafana.yml` file contains the Grafana configuration to add the Prometheus data source. This is how you connect the Grafana server to the Prometheus server. In the environment variables, you have set the Grafana admin user and password, which will be used to log in to the Grafana dashboard.
```yaml
apiVersion: 1
datasources:
- name: Prometheus (Main)
type: prometheus
url: http://prometheus:9090
isDefault: true
```
In the `grafana.yml` file, you have defined a Prometheus data source named `Prometheus (Main)`. The `type` field specifies the type of the data source, which is `prometheus`. The `url` field specifies the URL of the Prometheus server to fetch the metrics from. In this case, the URL is `http://prometheus:9090`. `prometheus` is the service name of the Prometheus server in the Docker Compose file. The `isDefault` field specifies whether the data source is the default data source in Grafana.
Apart from the services, the Docker Compose file also defines a volume named `grafana-data` to persist the Grafana data and a network named `go-network` to connect the services together. You have created a custom network `go-network` to connect the services together. The `driver: bridge` field specifies the network driver to use for the network.
### Building and running the services
Now that you have the Docker Compose file, you can build the services and run them together using Docker Compose.
To build and run the services, run the following command in the terminal:
```console
$ docker compose up
```
The `docker compose up` command builds the services defined in the Docker Compose file and runs them together. You will see the similar output in the terminal:
```console
✔ Network go-prometheus-monitoring_go-network Created 0.0s
✔ Container grafana Created 0.3s
✔ Container go-api Created 0.2s
✔ Container prometheus Created 0.3s
Attaching to go-api, grafana, prometheus
go-api | [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
go-api |
go-api | [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
go-api | - using env: export GIN_MODE=release
go-api | - using code: gin.SetMode(gin.ReleaseMode)
go-api |
go-api | [GIN-debug] GET /metrics --> main.PrometheusHandler.func1 (3 handlers)
go-api | [GIN-debug] GET /health --> main.main.func1 (4 handlers)
go-api | [GIN-debug] GET /v1/users --> main.main.func2 (4 handlers)
go-api | [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
go-api | Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
go-api | [GIN-debug] Listening and serving HTTP on :8000
prometheus | ts=2025-03-15T05:57:06.676Z caller=main.go:627 level=info msg="No time or size retention was set so using the default time retention" duration=15d
prometheus | ts=2025-03-15T05:57:06.678Z caller=main.go:671 level=info msg="Starting Prometheus Server" mode=server version="(version=2.55.0, branch=HEAD, revision=91d80252c3e528728b0f88d254dd720f6be07cb8)"
grafana | logger=settings t=2025-03-15T05:57:06.865335506Z level=info msg="Config overridden from command line" arg="default.log.mode=console"
grafana | logger=settings t=2025-03-15T05:57:06.865337131Z level=info msg="Config overridden from Environment variable" var="GF_PATHS_DATA=/var/lib/grafana"
grafana | logger=ngalert.state.manager t=2025-03-15T05:57:07.088956839Z level=info msg="State
.
.
grafana | logger=plugin.angulardetectorsprovider.dynamic t=2025-03-15T05:57:07.530317298Z level=info msg="Patterns update finished" duration=440.489125ms
```
The services will start running, and you can access the Golang application at `http://localhost:8000`, Prometheus at `http://localhost:9090/health`, and Grafana at `http://localhost:3000`. You can also check the running containers using the `docker ps` command.
```console
$ docker ps
```
### Summary
In this section, you learned how to connect services together using Docker Compose. You created a Docker Compose file to run multiple services together and connect them using networks. You also learned how to build and run the services using Docker Compose.
Related information:
- [Docker Compose overview](/manuals/compose/_index.md)
- [Compose file reference](/reference/compose-file/_index.md)
Next, you will learn how to develop the Golang application with Docker Compose and monitor it with Prometheus and Grafana.
### Next steps
In the next section, you will learn how to develop the Golang application with Docker. You will also learn how to use Docker Compose Watch to rebuild the image whenever you make changes to the code. Lastly, you will test the application and visualize the metrics in Grafana using Prometheus as the data source.
## Developing your application
In the last section, you saw how using Docker Compose, you can connect your services together. In this section, you will learn how to develop the Golang application with Docker. You will also see how to use Docker Compose Watch to rebuild the image whenever you make changes to the code. Lastly, you will test the application and visualize the metrics in Grafana using Prometheus as the data source.
### Developing the application
Now, if you make any changes to your Golang application locally, it needs to reflect in the container, right? To do that, one approach is use the `--build` flag in Docker Compose after making changes in the code. This will rebuild all the services which have the `build` instruction in the `compose.yml` file, in your case, the `api` service (Golang application).
```console
docker compose up --build
```
But, this is not the best approach. This is not efficient. Every time you make a change in the code, you need to rebuild manually. This is not is not a good flow for development.
The better approach is to use Docker Compose Watch. In the `compose.yml` file, under the service `api`, you have added the `develop` section. So, it's more like a hot reloading. Whenever you make changes to code (defined in `path`), it will rebuild the image (or restart depending on the action). This is how you can use it:
```yaml {hl_lines="17-20",linenos=true}
services:
api:
container_name: go-api
build:
context: .
dockerfile: Dockerfile
image: go-api:latest
ports:
- 8000:8000
networks:
- go-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 5
develop:
watch:
- path: .
action: rebuild
```
Once you have added the `develop` section in the `compose.yml` file, you can use the following command to start the development server:
```console
$ docker compose watch
```
Now, if you modify your `main.go` or any other file in the project, the `api` service will be rebuilt automatically. You will see the following output in the terminal:
```bash
Rebuilding service(s) ["api"] after changes were detected...
[+] Building 8.1s (15/15) FINISHED docker:desktop-linux
=> [api internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 704B 0.0s
=> [api internal] load metadata for docker.io/library/alpine:3.17 1.1s
.
=> => exporting manifest list sha256:89ebc86fd51e27c1da440dc20858ff55fe42211a1930c2d51bbdce09f430c7f1 0.0s
=> => naming to docker.io/library/go-api:latest 0.0s
=> => unpacking to docker.io/library/go-api:latest 0.0s
=> [api] resolving provenance for metadata file 0.0s
service(s) ["api"] successfully built
```
### Testing the application
Now that you have your application running, head over to the Grafana dashboard to visualize the metrics you are registering. Open your browser and navigate to `http://localhost:3000`. You will be greeted with the Grafana login page. The login credentials are the ones provided in Compose file.
Once you are logged in, you can create a new dashboard. While creating dashboard you will notice that is default data source is `Prometheus`. This is because you have already configured the data source in the `grafana.yml` file.
![The optional settings screen with the options specified.](../images/grafana-dash.png)
You can use different panels to visualize the metrics. This guide doesn't go into details of Grafana. You can refer to the [Grafana documentation](https://grafana.com/docs/grafana/latest/) for more information. There is a Bar Gauge panel to visualize the total number of requests from different endpoints. You used the `api_http_request_total` and `api_http_request_error_total` metrics to get the data.
![The optional settings screen with the options specified.](../images/grafana-panel.png)
You created this panel to visualize the total number of requests from different endpoints to compare the successful and failed requests. For all the good requests, the bar will be green, and for all the failed requests, the bar will be red. Plus it will also show the from which endpoint the request is coming, either it's a successful request or a failed request. If you want to use this panel, you can import the `dashboard.json` file from the repository you cloned.
### Summary
You've come to the end of this guide. You learned how to develop the Golang application with Docker. You also saw how to use Docker Compose Watch to rebuild the image whenever you make changes to the code. Lastly, you tested the application and visualized the metrics in Grafana using Prometheus as the data source.

View File

@@ -1,58 +0,0 @@
---
title: Go language-specific guide
linkTitle: Go
description: Containerize Go apps using Docker
keywords: docker, getting started, go, golang, language, dockerfile
summary: |
This guide teaches you how to containerize Go applications using Docker.
toc_min: 1
toc_max: 2
aliases:
- /language/golang/
- /guides/language/golang/
- /guides/golang/configure-ci-cd/
- /language/golang/configure-ci-cd/
- /guides/language/golang/configure-ci-cd/
- /guides/golang/deploy/
- /language/golang/deploy/
- /guides/language/golang/deploy/
languages: [go]
params:
time: 30 minutes
---
This guide will show you how to create, test, and deploy containerized Go applications using Docker.
> **Acknowledgment**
>
> Docker would like to thank [Oliver Frolovs](https://www.linkedin.com/in/ofr/) for his contribution to this guide.
## What will you learn?
In this guide, you’ll learn how to:
- Create a `Dockerfile` which contains the instructions for building a container image for a program written in Go.
- Run the image as a container in your local Docker instance and manage the container's lifecycle.
- Use multi-stage builds for building small images efficiently while keeping your Dockerfiles easy to read and maintain.
- Use Docker Compose to orchestrate running of multiple related containers together in a development environment.
## Prerequisites
Some basic understanding of Go and its toolchain is assumed. This isn't a Go tutorial. If you are new to the : languages:,
the [Go website](https://golang.org/) is a great place to explore,
so _go_ (pun intended) check it out!
You also must know some basic [Docker concepts](/get-started/docker-concepts/the-basics/what-is-a-container.md) as well as to
be at least vaguely familiar with the [Dockerfile format](/manuals/build/concepts/dockerfile.md).
Your Docker set-up must have BuildKit enabled. BuildKit is enabled by default for all users on [Docker Desktop](/manuals/desktop/_index.md).
If you have installed Docker Desktop, you don’t have to manually enable BuildKit. If you are running Docker on Linux,
please check out BuildKit [getting started](/manuals/build/buildkit/_index.md#getting-started) page.
Some familiarity with the command line is also expected.
## What's next?
The aim of this guide is to provide enough examples and instructions for you to containerize your own Go application and deploy it into the Cloud.
Start by building your first Go image.

View File

@@ -1,489 +0,0 @@
---
title: Build your Go image
linkTitle: Build images
weight: 5
keywords: containers, images, go, golang, dockerfiles, coding, build, push, run
description: Learn how to build your first Docker image by writing a Dockerfile
aliases:
- /get-started/golang/build-images/
- /language/golang/build-images/
- /guides/language/golang/build-images/
---
## Overview
In this section you're going to build a container image. The image includes
everything you need to run your application – the compiled application binary
file, the runtime, the libraries, and all other resources required by your
application.
## Required software
To complete this tutorial, you need the following:
- Docker running locally. Follow the [instructions to download and install Docker](/manuals/desktop/_index.md).
- An IDE or a text editor to edit files. [Visual Studio Code](https://code.visualstudio.com/) is a free and popular choice but you can use anything you feel comfortable with.
- A Git client. This guide uses a command-line based `git` client, but you are free to use whatever works for you.
- A command-line terminal application. The examples shown in this module are from the Linux shell, but they should work in PowerShell, Windows Command Prompt, or OS X Terminal with minimal, if any, modifications.
## Meet the example application
The example application is a caricature of a microservice. It is purposefully trivial to keep focus on learning the basics of containerization for Go applications.
The application offers two HTTP endpoints:
- It responds with a string containing a heart symbol (`<3`) to requests to `/`.
- It responds with `{"Status" : "OK"}` JSON to a request to `/health`.
It responds with HTTP error 404 to any other request.
The application listens on a TCP port defined by the value of environment variable `PORT`. The default value is `8080`.
The application is stateless.
The complete source code for the application is on GitHub: [github.com/docker/docker-gs-ping](https://github.com/docker/docker-gs-ping). You are encouraged to fork it and experiment with it as much as you like.
To continue, clone the application repository to your local machine:
```console
$ git clone https://github.com/docker/docker-gs-ping
```
The application's `main.go` file is straightforward, if you are familiar with Go:
```go
package main
import (
"net/http"
"os"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.GET("/", func(c echo.Context) error {
return c.HTML(http.StatusOK, "Hello, Docker! <3")
})
e.GET("/health", func(c echo.Context) error {
return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"})
})
httpPort := os.Getenv("PORT")
if httpPort == "" {
httpPort = "8080"
}
e.Logger.Fatal(e.Start(":" + httpPort))
}
// Simple implementation of an integer minimum
// Adapted from: https://gobyexample.com/testing-and-benchmarking
func IntMin(a, b int) int {
if a < b {
return a
}
return b
}
```
## Create a Dockerfile for the application
To build a container image with Docker, a `Dockerfile` with build instructions is required.
Begin your `Dockerfile` with the (optional) parser directive line that instructs BuildKit to
interpret your file according to the grammar rules for the specified version of the syntax.
You then tell Docker what base image you would like to use for your application:
```dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.19
```
Docker images can be inherited from other images. Therefore, instead of creating
your own base image from scratch, you can use the official Go image that already
has all necessary tools and libraries to compile and run a Go application.
> [!NOTE]
>
> If you are curious about creating your own base images, you can check out the following section of this guide: [creating base images](/manuals/build/building/base-images.md#create-a-base-image).
> Note, however, that this isn't necessary to continue with your task at hand.
Now that you have defined the base image for your upcoming container image, you
can begin building on top of it.
To make things easier when running the rest of your commands, create a directory
inside the image that you're building. This also instructs Docker to use this
directory as the default destination for all subsequent commands. This way you
don't have to type out full file paths in the `Dockerfile`, the relative paths
will be based on this directory.
```dockerfile
WORKDIR /app
```
Usually the very first thing you do once you’ve downloaded a project written in
Go is to install the modules necessary to compile it. Note, that the base image
has the toolchain already, but your source code isn't in it yet.
So before you can run `go mod download` inside your image, you need to get your
`go.mod` and `go.sum` files copied into it. Use the `COPY` command to do this.
In its simplest form, the `COPY` command takes two parameters. The first
parameter tells Docker what files you want to copy into the image. The last
parameter tells Docker where you want that file to be copied to.
Copy the `go.mod` and `go.sum` file into your project directory `/app` which,
owing to your use of `WORKDIR`, is the current directory (`./`) inside the
image. Unlike some modern shells that appear to be indifferent to the use of
trailing slash (`/`), and can figure out what the user meant (most of the time),
Docker's `COPY` command is quite sensitive in its interpretation of the trailing
slash.
```dockerfile
COPY go.mod go.sum ./
```
> [!NOTE]
>
> If you'd like to familiarize yourself with the trailing slash treatment by the
> `COPY` command, see [Dockerfile
> reference](/reference/dockerfile.md#copy). This trailing slash can
> cause issues in more ways than you can imagine.
Now that you have the module files inside the Docker image that you are
building, you can use the `RUN` command to run the command `go mod download`
there as well. This works exactly the same as if you were running `go` locally
on your machine, but this time these Go modules will be installed into a
directory inside the image.
```dockerfile
RUN go mod download
```
At this point, you have a Go toolchain version 1.19.x and all your Go
dependencies installed inside the image.
The next thing you need to do is to copy your source code into the image. You’ll
use the `COPY` command just like you did with your module files before.
```dockerfile
COPY *.go ./
```
This `COPY` command uses a wildcard to copy all files with `.go` extension
located in the current directory on the host (the directory where the `Dockerfile`
is located) into the current directory inside the image.
Now, to compile your application, use the familiar `RUN` command:
```dockerfile
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
```
This should be familiar. The result of that command will be a static application
binary named `docker-gs-ping` and located in the root of the filesystem of the
image that you are building. You could have put the binary into any other place
you desire inside that image, the root directory has no special meaning in this
regard. It's convenient to use it to keep the file paths short for improved
readability.
Now, all that is left to do is to tell Docker what command to run when your
image is used to start a container.
You do this with the `CMD` command:
```dockerfile
CMD ["/docker-gs-ping"]
```
Here's the complete `Dockerfile`:
```dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.19
# Set destination for COPY
WORKDIR /app
# Download Go modules
COPY go.mod go.sum ./
RUN go mod download
# Copy the source code. Note the slash at the end, as explained in
# https://docs.docker.com/reference/dockerfile/#copy
COPY *.go ./
# Build
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
# Optional:
# To bind to a TCP port, runtime parameters must be supplied to the docker command.
# But we can document in the Dockerfile what ports
# the application is going to listen on by default.
# https://docs.docker.com/reference/dockerfile/#expose
EXPOSE 8080
# Run
CMD ["/docker-gs-ping"]
```
The `Dockerfile` may also contain comments. They always begin with a `#` symbol,
and must be at the beginning of a line. Comments are there for your convenience
to allow documenting your `Dockerfile`.
There is also a concept of Dockerfile directives, such as the `syntax` directive
you added. The directives must always be at the very top of the `Dockerfile`, so
when adding comments, make sure that the comments follow after any directives
that you may have used:
```dockerfile
# syntax=docker/dockerfile:1
# A sample microservice in Go packaged into a container image.
FROM golang:1.19
# ...
```
## Build the image
Now that you've created your `Dockerfile`, build an image from it. The `docker
build` command creates Docker images from the `Dockerfile` and a context. A
build context is the set of files located in the specified path or URL. The
Docker build process can access any of the files located in the context.
The build command optionally takes a `--tag` flag. This flag is used to label
the image with a string value, which is easy for humans to read and recognize.
If you don't pass a `--tag`, Docker will use `latest` as the default value.
Build your first Docker image.
```console
$ docker build --tag docker-gs-ping .
```
The build process will print some diagnostic messages as it goes through the build steps.
The following is an example of what these messages may look like.
```console
[+] Building 2.2s (15/15) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 701B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1 1.1s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:39b85bbfa7536a5feceb7372a0817649ecb2724562a38360f4d6a7782a409b14 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load metadata for docker.io/library/golang:1.19 0.7s
=> [1/6] FROM docker.io/library/golang:1.19@sha256:5d947843dde82ba1df5ac1b2ebb70b203d106f0423bf5183df3dc96f6bc5a705 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 6.08kB 0.0s
=> CACHED [2/6] WORKDIR /app 0.0s
=> CACHED [3/6] COPY go.mod go.sum ./ 0.0s
=> CACHED [4/6] RUN go mod download 0.0s
=> CACHED [5/6] COPY *.go ./ 0.0s
=> CACHED [6/6] RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:ede8ff889a0d9bc33f7a8da0673763c887a258eb53837dd52445cdca7b7df7e3 0.0s
=> => naming to docker.io/library/docker-gs-ping 0.0s
```
Your exact output will vary, but provided there aren't any errors, you should
see the word `FINISHED` in the first line of output. This means Docker has
successfully built your image named `docker-gs-ping`.
## View local images
To see the list of images you have on your local machine, you have two options.
One is to use the CLI and the other is to use [Docker
Desktop](/manuals/desktop/_index.md). Since you're working in the
terminal, take a look at listing images with the CLI.
To list images, run the `docker image ls`command (or the `docker images` shorthand):
```console
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-gs-ping latest 7f153fbcc0a8 2 minutes ago 1.11GB
...
```
Your exact output may vary, but you should see the `docker-gs-ping` image with
the `latest` tag. Because you didn't specify a custom tag when you built your
image, Docker assumed that the tag would be `latest`, which is a special value.
## Tag images
An image name is made up of slash-separated name components. Name components may
contain lowercase letters, digits, and separators. A separator is defined as a
period, one or two underscores, or one or more dashes. A name component may not
start or end with a separator.
An image is made up of a manifest and a list of layers. In simple terms, a tag
points to a combination of these artifacts. You can have multiple tags for the
image and, in fact, most images have multiple tags. Create a second tag
for the image you built and take a look at its layers.
Use the `docker image tag` (or `docker tag` shorthand) command to create a new
tag for your image. This command takes two arguments; the first argument is the
source image, and the second is the new tag to create. The following command
creates a new `docker-gs-ping:v1.0` tag for the `docker-gs-ping:latest` you
built:
```console
$ docker image tag docker-gs-ping:latest docker-gs-ping:v1.0
```
The Docker `tag` command creates a new tag for the image. It doesn't create a
new image. The tag points to the same image and is another way to reference
the image.
Now run the `docker image ls` command again to see the updated list of local
images:
```console
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-gs-ping latest 7f153fbcc0a8 6 minutes ago 1.11GB
docker-gs-ping v1.0 7f153fbcc0a8 6 minutes ago 1.11GB
...
```
You can see that you have two images that start with `docker-gs-ping`. You know
they're the same image because if you look at the `IMAGE ID` column, you can
see that the values are the same for the two images. This value is a unique
identifier Docker uses internally to identify the image.
Remove the tag that you just created. To do this, you’ll use the
`docker image rm` command, or the shorthand `docker rmi` (which stands for
"remove image"):
```console
$ docker image rm docker-gs-ping:v1.0
Untagged: docker-gs-ping:v1.0
```
Notice that the response from Docker tells you that the image hasn't been
removed but only untagged.
Verify this by running the following command:
```console
$ docker image ls
```
You will see that the tag `v1.0` is no longer in the list of images kept by your Docker instance.
```text
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-gs-ping latest 7f153fbcc0a8 7 minutes ago 1.11GB
...
```
The tag `v1.0` has been removed but you still have the `docker-gs-ping:latest`
tag available on your machine, so the image is there.
## Multi-stage builds
You may have noticed that your `docker-gs-ping` image weighs in at over a
gigabyte, which is a lot for a tiny compiled Go application. You may also be
wondering what happened to the full suite of Go tools, including the compiler,
after you had built your image.
The answer is that the full toolchain is still there, in the container image.
Not only this is inconvenient because of the large file size, but it may also
present a security risk when the container is deployed.
These two issues can be solved by using [multi-stage builds](/manuals/build/building/multi-stage.md).
In a nutshell, a multi-stage build can carry over the artifacts from one build stage into another,
and every build stage can be instantiated from a different base image.
Thus, in the following example, you are going to use a full-scale official Go
image to build your application. Then you'll copy the application binary into
another image whose base is very lean and doesn't include the Go toolchain or
other optional components.
The `Dockerfile.multistage` in the sample application's repository has the
following content:
```dockerfile
# syntax=docker/dockerfile:1
# Build the application from source
FROM golang:1.19 AS build-stage
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o /docker-gs-ping
# Run the tests in the container
FROM build-stage AS run-test-stage
RUN go test -v ./...
# Deploy the application binary into a lean image
FROM gcr.io/distroless/base-debian11 AS build-release-stage
WORKDIR /
COPY --from=build-stage /docker-gs-ping /docker-gs-ping
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/docker-gs-ping"]
```
Since you have two Dockerfiles now, you have to tell Docker what Dockerfile
you'd like to use to build the image. Tag the new image with `multistage`. This
tag (like any other, apart from `latest`) has no special meaning for Docker,
it's something you chose.
```console
$ docker build -t docker-gs-ping:multistage -f Dockerfile.multistage .
```
Comparing the sizes of `docker-gs-ping:multistage` and `docker-gs-ping:latest`
you see a few orders-of-magnitude difference.
```console
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-gs-ping multistage e3fdde09f172 About a minute ago 28.1MB
docker-gs-ping latest 336a3f164d0f About an hour ago 1.11GB
```
This is so because the ["distroless"](https://github.com/GoogleContainerTools/distroless)
base image that you have used in the second stage of the build is very barebones and is designed for lean deployments of static binaries.
There's much more to multi-stage builds, including the possibility of multi-architecture builds,
so feel free to check out [multi-stage builds](/manuals/build/building/multi-stage.md). This is, however, not essential for your progress here.
## Next steps
In this module, you met your example application and built and container image
for it.
In the next module, you’ll take a look at how to run your image as a container.

View File

@@ -1,733 +0,0 @@
---
title: Use containers for Go development
linkTitle: Develop your app
weight: 20
keywords: get started, go, golang, local, development
description: Learn how to develop your application locally.
aliases:
- /get-started/golang/develop/
- /language/golang/develop/
- /guides/language/golang/develop/
---
## Prerequisites
Work through the steps of the [run your image as a container](run-containers.md) module to learn how to manage the lifecycle of your containers.
## Introduction
In this module, you'll take a look at running a database engine in a container and connecting it to the extended version of the example application. You are going to see some options for keeping persistent data and for wiring up the containers to talk to one another. Finally, you'll learn how to use Docker Compose to manage such multi-container local development environments effectively.
## Local database and containers
The database engine you are going to use is called [CockroachDB](https://www.cockroachlabs.com/product/). It is a modern, Cloud-native, distributed SQL database.
Instead of compiling CockroachDB from the source code or using the operating system's native package manager to install CockroachDB, you are going to use the [Docker image for CockroachDB](https://hub.docker.com/r/cockroachdb/cockroach) and run it in a container.
CockroachDB is compatible with PostgreSQL to a significant extent, and shares many conventions with the latter, particularly the default names for the environment variables. So, if you are familiar with Postgres, don't be surprised if you see some familiar environment variable names. The Go modules that work with Postgres, such as [pgx](https://pkg.go.dev/github.com/jackc/pgx), [pq](https://pkg.go.dev/github.com/lib/pq), [GORM](https://gorm.io/index.html), and [upper/db](https://upper.io/v4/) also work with CockroachDB.
For more information on the relation between Go and CockroachDB, refer to the [CockroachDB documentation](https://www.cockroachlabs.com/docs/v20.2/build-a-go-app-with-cockroachdb.html), although this isn't necessary to continue with the present guide.
### Storage
The point of a database is to have a persistent store of data. [Volumes](/manuals/engine/storage/volumes.md) are the preferred mechanism for persisting data generated by and used by Docker containers. Thus, before you start CockroachDB, create the volume for it.
To create a managed volume, run :
```console
$ docker volume create roach
roach
```
You can view the list of all managed volumes in your Docker instance with the following command:
```console
$ docker volume list
DRIVER VOLUME NAME
local roach
```
### Networking
The example application and the database engine are going to talk to one another over the network. There are different kinds of network configuration possible, and you're going to use what's called a user-defined bridge network. It is going to provide you with a DNS lookup service so that you can refer to your database engine container by its hostname.
The following command creates a new bridge network named `mynet`:
```console
$ docker network create -d bridge mynet
51344edd6430b5acd121822cacc99f8bc39be63dd125a3b3cd517b6485ab7709
```
As it was the case with the managed volumes, there is a command to list all networks set up in your Docker instance:
```console
$ docker network list
NETWORK ID NAME DRIVER SCOPE
0ac2b1819fa4 bridge bridge local
51344edd6430 mynet bridge local
daed20bbecce host host local
6aee44f40a39 none null local
```
Your bridge network `mynet` has been created successfully. The other three networks, named `bridge`, `host`, and `none` are the default networks and they had been created by the Docker itself. While it's not relevant to this guide, you can learn more about Docker networking in the [networking overview](/manuals/engine/network/_index.md) section.
### Choose good names for volumes and networks
As the saying goes, there are only two hard things in Computer Science: cache invalidation and naming things. And off-by-one errors.
When choosing a name for a network or a managed volume, it's best to choose a name that's indicative of the intended purpose. This guide aims for brevity, so it used short, generic names.
### Start the database engine
Now that the housekeeping chores are done, you can run CockroachDB in a container and attach it to the volume and network you had just created. When you run the following command, Docker will pull the image from Docker Hub and run it for you locally:
```console
$ docker run -d \
--name roach \
--hostname db \
--network mynet \
-p 26257:26257 \
-p 8080:8080 \
-v roach:/cockroach/cockroach-data \
cockroachdb/cockroach:latest-v25.4 start-single-node \
--insecure
# ... output omitted ...
```
Notice a clever use of the tag `latest-v25.4` to make sure that you're pulling the latest patch version of 25.4. The diversity of available tags depend on the image maintainer. Here, your intent was to have the latest patched version of CockroachDB while not straying too far away from the known working version as the time goes by. To see the tags available for the CockroachDB image, you can go to the [CockroachDB page on Docker Hub](https://hub.docker.com/r/cockroachdb/cockroach/tags).
### Configure the database engine
Now that the database engine is live, there is some configuration to do before your application can begin using it. Fortunately, it's not a lot. You must:
1. Create a blank database.
2. Register a new user account with the database engine.
3. Grant that new user access rights to the database.
You can do that with the help of CockroachDB built-in SQL shell. To start the SQL shell in the same container where the database engine is running, type:
```console
$ docker exec -it roach ./cockroach sql --insecure
```
1. In the SQL shell, create the database that the example application is going to use:
```sql
CREATE DATABASE mydb;
```
2. Register a new SQL user account with the database engine. Use the username `totoro`.
```sql
CREATE USER totoro;
```
3. Give the new user the necessary permissions:
```sql
GRANT ALL ON DATABASE mydb TO totoro;
```
4. Type `quit` to exit the shell.
The following is an example of interaction with the SQL shell.
```console
$ sudo docker exec -it roach ./cockroach sql --insecure
#
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
# Server version: CockroachDB CCL v20.1.15 (x86_64-unknown-linux-gnu, built 2021/04/26 16:11:58, go1.13.9) (same version as client)
# Cluster ID: 7f43a490-ccd6-4c2a-9534-21f393ca80ce
#
# Enter \? for a brief introduction.
#
root@:26257/defaultdb> CREATE DATABASE mydb;
CREATE DATABASE
Time: 22.985478ms
root@:26257/defaultdb> CREATE USER totoro;
CREATE ROLE
Time: 13.921659ms
root@:26257/defaultdb> GRANT ALL ON DATABASE mydb TO totoro;
GRANT
Time: 14.217559ms
root@:26257/defaultdb> quit
oliver@hki:~$
```
### Meet the example application
Now that you have started and configured the database engine, you can switch your attention to the application.
The example application for this module is an extended version of `docker-gs-ping` application you've used in the previous modules. You have two options:
- You can update your local copy of `docker-gs-ping` to match the new extended version presented in this chapter; or
- You can clone the [docker/docker-gs-ping-dev](https://github.com/docker/docker-gs-ping-dev) repository. This latter approach is recommended.
To checkout the example application, run:
```console
$ git clone https://github.com/docker/docker-gs-ping-dev.git
# ... output omitted ...
```
The application's `main.go` now includes database initialization code, as well as the code to implement a new business requirement:
- An HTTP `POST` request to `/send` containing a `{ "value" : string }` JSON must save the value to the database.
You also have an update for another business requirement. The requirement was:
- The application responds with a text message containing a heart symbol ("`<3`") on requests to `/`.
And now it's going to be:
- The application responds with the string containing the count of messages stored in the database, enclosed in the parentheses.
Example output: `Hello, Docker! (7)`
The full source code listing of `main.go` follows.
```go
package main
import (
"context"
"database/sql"
"fmt"
"log"
"net/http"
"os"
"github.com/cenkalti/backoff/v4"
"github.com/cockroachdb/cockroach-go/v2/crdb"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
db, err := initStore()
if err != nil {
log.Fatalf("failed to initialize the store: %s", err)
}
defer db.Close()
e.GET("/", func(c echo.Context) error {
return rootHandler(db, c)
})
e.GET("/ping", func(c echo.Context) error {
return c.JSON(http.StatusOK, struct{ Status string }{Status: "OK"})
})
e.POST("/send", func(c echo.Context) error {
return sendHandler(db, c)
})
httpPort := os.Getenv("HTTP_PORT")
if httpPort == "" {
httpPort = "8080"
}
e.Logger.Fatal(e.Start(":" + httpPort))
}
type Message struct {
Value string `json:"value"`
}
func initStore() (*sql.DB, error) {
pgConnString := fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=disable",
os.Getenv("PGHOST"),
os.Getenv("PGPORT"),
os.Getenv("PGDATABASE"),
os.Getenv("PGUSER"),
os.Getenv("PGPASSWORD"),
)
var (
db *sql.DB
err error
)
openDB := func() error {
db, err = sql.Open("postgres", pgConnString)
return err
}
err = backoff.Retry(openDB, backoff.NewExponentialBackOff())
if err != nil {
return nil, err
}
if _, err := db.Exec(
"CREATE TABLE IF NOT EXISTS message (value TEXT PRIMARY KEY)"); err != nil {
return nil, err
}
return db, nil
}
func rootHandler(db *sql.DB, c echo.Context) error {
r, err := countRecords(db)
if err != nil {
return c.HTML(http.StatusInternalServerError, err.Error())
}
return c.HTML(http.StatusOK, fmt.Sprintf("Hello, Docker! (%d)\n", r))
}
func sendHandler(db *sql.DB, c echo.Context) error {
m := &Message{}
if err := c.Bind(m); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
err := crdb.ExecuteTx(context.Background(), db, nil,
func(tx *sql.Tx) error {
_, err := tx.Exec(
"INSERT INTO message (value) VALUES ($1) ON CONFLICT (value) DO UPDATE SET value = excluded.value",
m.Value,
)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
return nil
})
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
return c.JSON(http.StatusOK, m)
}
func countRecords(db *sql.DB) (int, error) {
rows, err := db.Query("SELECT COUNT(*) FROM message")
if err != nil {
return 0, err
}
defer rows.Close()
count := 0
for rows.Next() {
if err := rows.Scan(&count); err != nil {
return 0, err
}
rows.Close()
}
return count, nil
}
```
The repository also includes the `Dockerfile`, which is almost exactly the same as the multi-stage `Dockerfile` introduced in the previous modules. It uses the official Docker Go image to build the application and then builds the final image by placing the compiled binary into the much slimmer, distroless image.
Regardless of whether you had updated the old example application, or checked out the new one, this new Docker image has to be built to reflect the changes to the application source code.
### Build the application
You can build the image with the familiar `build` command:
```console
$ docker build --tag docker-gs-ping-roach .
```
### Run the application
Now, run your container. This time you'll need to set some environment variables so that your application knows how to access the database. For now, you’ll do this right in the `docker run` command. Later you'll see a more convenient method with Docker Compose.
> [!NOTE]
>
> Since you're running your CockroachDB cluster in insecure mode, the value for the password can be anything.
>
> In production, don't run in insecure mode.
```console
$ docker run -it --rm -d \
--network mynet \
--name rest-server \
-p 80:8080 \
-e PGUSER=totoro \
-e PGPASSWORD=myfriend \
-e PGHOST=db \
-e PGPORT=26257 \
-e PGDATABASE=mydb \
docker-gs-ping-roach
```
There are a few points to note about this command.
- You map container port `8080` to host port `80` this time. Thus, for `GET` requests you can get away with literally `curl localhost`:
```console
$ curl localhost
Hello, Docker! (0)
```
Or, if you prefer, a proper URL would work just as well:
```console
$ curl http://localhost/
Hello, Docker! (0)
```
- The total number of stored messages is `0` for now. This is fine, because you haven't posted anything to your application yet.
- You refer to the database container by its hostname, which is `db`. This is why you had `--hostname db` when you started the database container.
- The actual password doesn't matter, but it must be set to something to avoid confusing the example application.
- The container you've just run is named `rest-server`. These names are useful for managing the container lifecycle:
```console
# Don't do this just yet, it's only an example:
$ docker container rm --force rest-server
```
### Test the application
In the previous section, you've already tested querying your application with `GET` and it returned zero for the stored message counter. Now, post some messages to it:
```console
$ curl --request POST \
--url http://localhost/send \
--header 'content-type: application/json' \
--data '{"value": "Hello, Docker!"}'
```
The application responds with the contents of the message, which means it has been saved in the database:
```json
{ "value": "Hello, Docker!" }
```
Send another message:
```console
$ curl --request POST \
--url http://localhost/send \
--header 'content-type: application/json' \
--data '{"value": "Hello, Oliver!"}'
```
And again, you get the value of the message back:
```json
{ "value": "Hello, Oliver!" }
```
Run curl and see what the message counter says:
```console
$ curl localhost
Hello, Docker! (2)
```
In this example, you sent two messages and the database kept them. Or has it? Stop and remove all your containers, but not the volumes, and try again.
First, stop the containers:
```console
$ docker container stop rest-server roach
rest-server
roach
```
Then, remove them:
```console
$ docker container rm rest-server roach
rest-server
roach
```
Verify that they're gone:
```console
$ docker container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```
And start them again, database first:
```console
$ docker run -d \
--name roach \
--hostname db \
--network mynet \
-p 26257:26257 \
-p 8080:8080 \
-v roach:/cockroach/cockroach-data \
cockroachdb/cockroach:latest-v25.4 start-single-node \
--insecure
```
And the service next:
```console
$ docker run -it --rm -d \
--network mynet \
--name rest-server \
-p 80:8080 \
-e PGUSER=totoro \
-e PGPASSWORD=myfriend \
-e PGHOST=db \
-e PGPORT=26257 \
-e PGDATABASE=mydb \
docker-gs-ping-roach
```
Lastly, query your service:
```console
$ curl localhost
Hello, Docker! (2)
```
Great! The count of records from the database is correct although you haven't only stopped the containers, but you've also removed them before starting new instances. The difference is in the managed volume for CockroachDB, which you reused. The new CockroachDB container has read the database files from the disk, just as it normally would if it were running outside the container.
### Wind down everything
Remember, that you're running CockroachDB in insecure mode. Now that you've built and tested your application, it's time to wind everything down before moving on. You can list the containers that you are running with the `list` command:
```console
$ docker container list
```
Now that you know the container IDs, you can use `docker container stop` and `docker container rm`, as demonstrated in the previous modules.
Stop the CockroachDB and `docker-gs-ping-roach` containers before moving on.
## Better productivity with Docker Compose
At this point, you might be wondering if there is a way to avoid having to deal with long lists of arguments to the `docker` command. The toy example you used in this series requires five environment variables to define the connection to the database. A real application might need many, many more. Then there is also a question of dependencies. Ideally, you want to make sure that the database is started before your application is run. And spinning up the database instance may require another Docker command with many options. But there is a better way to orchestrate these deployments for local development purposes.
In this section, you'll create a Docker Compose file to start your `docker-gs-ping-roach` application and CockroachDB database engine with a single command.
### Configure Docker Compose
In your application's directory, create a new text file named `compose.yaml` with the following content.
```yaml
services:
docker-gs-ping-roach:
depends_on:
- roach
build:
context: .
container_name: rest-server
hostname: rest-server
networks:
- mynet
ports:
- 80:8080
environment:
- PGUSER=${PGUSER:-totoro}
- PGPASSWORD=${PGPASSWORD:?database password not set}
- PGHOST=${PGHOST:-db}
- PGPORT=${PGPORT:-26257}
- PGDATABASE=${PGDATABASE:-mydb}
deploy:
restart_policy:
condition: on-failure
roach:
image: cockroachdb/cockroach:latest-v25.4
container_name: roach
hostname: db
networks:
- mynet
ports:
- 26257:26257
- 8080:8080
volumes:
- roach:/cockroach/cockroach-data
command: start-single-node --insecure
volumes:
roach:
networks:
mynet:
driver: bridge
```
This Docker Compose configuration is super convenient as you don't have to type all the parameters to pass to the `docker run` command. You can declaratively do that in the Docker Compose file. The [Docker Compose documentation pages](/manuals/compose/_index.md) are quite extensive and include a full reference for the Docker Compose file format.
### The `.env` file
Docker Compose will automatically read environment variables from a `.env` file if it's available. Since your Compose file requires `PGPASSWORD` to be set, add the following content to the `.env` file:
```bash
PGPASSWORD=whatever
```
The exact value doesn't really matter for this example, because you run CockroachDB in insecure mode. Make sure you set the variable to some value to avoid getting an error.
### Merging Compose files
The filename `compose.yaml` is the default filename which `docker compose` command recognizes if no `-f` flag is provided. This means you can have multiple Docker Compose files if your environment has such requirements. Furthermore, Docker Compose files are composable, so multiple files can be specified on the command line to merge parts of the configuration together. The following list shows a few examples of scenarios where such a feature would be useful:
- Using a bind mount for the source code for local development but not when running the CI tests;
- Switching between using a pre-built image for the frontend for some API application vs creating a bind mount for source code;
- Adding additional services for integration testing;
- And many more...
You aren't going to cover any of these advanced use cases here.
### Variable substitution in Docker Compose
One of the really cool features of Docker Compose is [variable substitution](/reference/compose-file/interpolation.md). You can see some examples in the Compose file, `environment` section. By means of an example:
- `PGUSER=${PGUSER:-totoro}` means that inside the container, the environment variable `PGUSER` shall be set to the same value as it has on the host machine where Docker Compose is run. If there is no environment variable with this name on the host machine, the variable inside the container gets the default value of `totoro`.
- `PGPASSWORD=${PGPASSWORD:?database password not set}` means that if the environment variable `PGPASSWORD` isn't set on the host, Docker Compose will display an error. This is OK, because you don't want to hard-code default values for the password. You set the password value in the `.env` file, which is local to your machine. It is always a good idea to add `.env` to `.gitignore` to prevent the secrets being checked into the version control.
Other ways of dealing with undefined or empty values exist, as documented in the [variable substitution](/reference/compose-file/interpolation.md) section of the Docker documentation.
### Validating Docker Compose configuration
Before you apply changes made to a Compose configuration file, there is an opportunity to validate the content of the configuration file with the following command:
```console
$ docker compose config
```
When this command is run, Docker Compose reads the file `compose.yaml`, parses it into a data structure in memory, validates where possible, and prints back the reconstruction of that configuration file from its internal representation. If this isn't possible due to errors, Docker prints an error message instead.
### Build and run the application using Docker Compose
Start your application and confirm that it's running.
```console
$ docker compose up --build
```
You passed the `--build` flag so Docker will compile your image and then start it.
> [!NOTE]
>
> Docker Compose is a useful tool, but it has its own quirks. For example, no rebuild is triggered on the update to the source code unless the `--build` flag is provided. It is a very common pitfall to edit one's source code, and forget to use the `--build` flag when running `docker compose up`.
Since your set-up is now run by Docker Compose, it has assigned it a project name, so you get a new volume for your CockroachDB instance. This means that your application will fail to connect to the database, because the database doesn't exist in this new volume. The terminal displays an authentication error for the database:
```text
# ... omitted output ...
rest-server | 2021/05/10 00:54:25 failed to initialise the store: pq: password authentication failed for user totoro
roach | *
roach | * INFO: Replication was disabled for this cluster.
roach | * When/if adding nodes in the future, update zone configurations to increase the replication factor.
roach | *
roach | CockroachDB node starting at 2021-05-10 00:54:26.398177 +0000 UTC (took 3.0s)
roach | build: CCL v20.1.15 @ 2021/04/26 16:11:58 (go1.13.9)
roach | webui: http://db:8080
roach | sql: postgresql://root@db:26257?sslmode=disable
roach | RPC client flags: /cockroach/cockroach <client cmd> --host=db:26257 --insecure
roach | logs: /cockroach/cockroach-data/logs
roach | temp dir: /cockroach/cockroach-data/cockroach-temp349434348
roach | external I/O path: /cockroach/cockroach-data/extern
roach | store[0]: path=/cockroach/cockroach-data
roach | storage engine: rocksdb
roach | status: initialized new cluster
roach | clusterID: b7b1cb93-558f-4058-b77e-8a4ddb329a88
roach | nodeID: 1
rest-server exited with code 0
rest-server | 2021/05/10 00:54:25 failed to initialise the store: pq: password authentication failed for user totoro
rest-server | 2021/05/10 00:54:26 failed to initialise the store: pq: password authentication failed for user totoro
rest-server | 2021/05/10 00:54:29 failed to initialise the store: pq: password authentication failed for user totoro
rest-server | 2021/05/10 00:54:25 failed to initialise the store: pq: password authentication failed for user totoro
rest-server | 2021/05/10 00:54:26 failed to initialise the store: pq: password authentication failed for user totoro
rest-server | 2021/05/10 00:54:29 failed to initialise the store: pq: password authentication failed for user totoro
rest-server exited with code 1
# ... omitted output ...
```
Because of the way you set up your deployment using `restart_policy`, the failing container is being restarted every 20 seconds. So, in order to fix the problem, you need to log in to the database engine and create the user. You've done it before in [Configure the database engine](#configure-the-database-engine).
This isn't a big deal. All you have to do is to connect to CockroachDB instance and run the three SQL commands to create the database and the user, as described in [Configure the database engine](#configure-the-database-engine).
So, log in to the database engine from another terminal:
```console
$ docker exec -it roach ./cockroach sql --insecure
```
And run the same commands as before to create the database `mydb`, the user `totoro`, and to grant that user necessary permissions. Once you do that (and the example application container is automatically restarts), the `rest-service` stops failing and restarting and the console goes quiet.
It would have been possible to connect the volume that you had previously used, but for the purposes of this example it's more trouble than it's worth and it also provided an opportunity to show how to introduce resilience into your deployment via the `restart_policy` Compose file feature.
### Testing the application
Now, test your API endpoint. In the new terminal, run the following command:
```console
$ curl http://localhost/
```
You should receive the following response:
```json
Hello, Docker! (0)
```
### Shutting down
To stop the containers started by Docker Compose, press `ctrl+c` in the terminal where you ran `docker compose up`. To remove those containers after they've been stopped, run `docker compose down`.
### Detached mode
You can run containers started by the `docker compose` command in detached mode, just as you would with the `docker` command, by using the `-d` flag.
To start the stack, defined by the Compose file in detached mode, run:
```console
$ docker compose up --build -d
```
Then, you can use `docker compose stop` to stop the containers and `docker compose down` to remove them.
## Further exploration
You can run `docker compose` to see what other commands are available.
## Wrap up
There are some tangential, yet interesting points that were purposefully not covered in this chapter. For the more adventurous reader, this section offers some pointers for further study.
### Persistent storage
A managed volume isn't the only way to provide your container with persistent storage. It is highly recommended to get acquainted with available storage options and their use cases, covered in [Manage data in Docker](/manuals/engine/storage/_index.md).
### CockroachDB clusters
You ran a single instance of CockroachDB, which was enough for this example. But, it's possible to run a CockroachDB cluster, which is made of multiple instances of CockroachDB, each instance running in its own container. Since CockroachDB engine is distributed by design, it would have taken surprisingly little change to your procedure to run a cluster with multiple nodes.
Such distributed set-up offers interesting possibilities, such as applying Chaos Engineering techniques to simulate parts of the cluster failing and evaluating your application's ability to cope with such failures.
If you are interested in experimenting with CockroachDB clusters, check out:
- [Start a CockroachDB Cluster in Docker](https://www.cockroachlabs.com/docs/v20.2/start-a-local-cluster-in-docker-mac.html) article; and
- Documentation for Docker Compose keywords [`deploy`](/reference/compose-file/legacy-versions.md) and [`replicas`](/reference/compose-file/legacy-versions.md).
### Other databases
Since you didn't run a cluster of CockroachDB instances, you might be wondering whether you could have used a non-distributed database engine. The answer is 'yes', and if you were to pick a more traditional SQL database, such as [PostgreSQL](https://www.postgresql.org/), the process described in this chapter would have been very similar.
## Next steps
In this module, you set up a containerized development environment with your application and the database engine running in different containers. You also wrote a Docker Compose file which links the two containers together and provides for easy starting up and tearing down of the development environment.
In the next module, you'll take a look at one possible approach to running functional tests in Docker.

File diff suppressed because it is too large Load Diff

View File

@@ -1,210 +0,0 @@
---
title: Run your Go image as a container
linkTitle: Run containers
weight: 10
keywords: get started, go, golang, run, container
description: Learn how to run the image as a container.
aliases:
- /get-started/golang/run-containers/
- /language/golang/run-containers/
- /guides/language/golang/run-containers/
---
## Prerequisites
Work through the steps to containerize a Go application in [Build your Go image](build-images.md).
## Overview
In the previous module you created a `Dockerfile` for your example application and then you created your Docker image using the command `docker build`. Now that you have the image, you can run that image and see if your application is running correctly.
A container is a normal operating system process except that this process is isolated and has its own file system, its own networking, and its own isolated process tree separate from the host.
To run an image inside of a container, you use the `docker run` command. It requires one parameter and that's the image name. Start your image and make sure it's running correctly. Run the following command in your terminal.
```console
$ docker run docker-gs-ping
```
```text
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.10.2
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:8080
```
When you run this command, you’ll notice that you weren't returned to the command prompt. This is because your application is a REST server and will run in a loop waiting for incoming requests without returning control back to the OS until you stop the container.
Make a GET request to the server using the curl command.
```console
$ curl http://localhost:8080/
curl: (7) Failed to connect to localhost port 8080: Connection refused
```
Your curl command failed because the connection to your server was refused.
Meaning that you weren't able to connect to localhost on port 8080. This is
expected because your container is running in isolation which includes
networking. Stop the container and restart with port 8080 published on your
local network.
To stop the container, press ctrl-c. This will return you to the terminal prompt.
To publish a port for your container, you’ll use the `--publish` flag (`-p` for short) on the `docker run` command. The format of the `--publish` command is `[host_port]:[container_port]`. So if you wanted to expose port `8080` inside the container to port `3000` outside the container, you would pass `3000:8080` to the `--publish` flag.
Start the container and expose port `8080` to port `8080` on the host.
```console
$ docker run --publish 8080:8080 docker-gs-ping
```
Now, rerun the curl command.
```console
$ curl http://localhost:8080/
Hello, Docker! <3
```
Success! You were able to connect to the application running inside of your container on port 8080. Switch back to the terminal where your container is running and you should see the `GET` request logged to the console.
Press `ctrl-c` to stop the container.
## Run in detached mode
This is great so far, but your sample application is a web server and you
shouldn't have to have your terminal connected to the container. Docker can run
your container in detached mode in the background. To do this, you can use the
`--detach` or `-d` for short. Docker will start your container the same as
before but this time will detach from the container and return you to the
terminal prompt.
```console
$ docker run -d -p 8080:8080 docker-gs-ping
d75e61fcad1e0c0eca69a3f767be6ba28a66625ce4dc42201a8a323e8313c14e
```
Docker started your container in the background and printed the container ID on the terminal.
Again, make sure that your container is running. Run the same `curl` command:
```console
$ curl http://localhost:8080/
Hello, Docker! <3
```
## List containers
Since you ran your container in the background, how do you know if your container is running or what other containers are running on your machine? Well, to see a list of containers running on your machine, run `docker ps`. This is similar to how the ps command is used to see a list of processes on a Linux machine.
```console
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d75e61fcad1e docker-gs-ping "/docker-gs-ping" 41 seconds ago Up 40 seconds 0.0.0.0:8080->8080/tcp inspiring_ishizaka
```
The `ps` command tells you a bunch of stuff about your running containers. You can see the container ID, the image running inside the container, the command that was used to start the container, when it was created, the status, ports that are exposed, and the names of the container.
You are probably wondering where the name of your container is coming from. Since you didn’t provide a name for the container when you started it, Docker generated a random name. You'll fix this in a minute but first you need to stop the container. To stop the container, run the `docker stop` command, passing the container's name or ID.
```console
$ docker stop inspiring_ishizaka
inspiring_ishizaka
```
Now rerun the `docker ps` command to see a list of running containers.
```console
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```
## Stop, start, and name containers
Docker containers can be started, stopped and restarted. When you stop a container, it's not removed but the status is changed to stopped and the process inside of the container is stopped. When you ran the `docker ps` command, the default output is to only show running containers. If you pass the `--all` or `-a` for short, you will see all containers on your system, including stopped containers and running containers.
```console
$ docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d75e61fcad1e docker-gs-ping "/docker-gs-ping" About a minute ago Exited (2) 23 seconds ago inspiring_ishizaka
f65dbbb9a548 docker-gs-ping "/docker-gs-ping" 3 minutes ago Exited (2) 2 minutes ago wizardly_joliot
aade1bf3d330 docker-gs-ping "/docker-gs-ping" 3 minutes ago Exited (2) 3 minutes ago magical_carson
52d5ce3c15f0 docker-gs-ping "/docker-gs-ping" 9 minutes ago Exited (2) 3 minutes ago gifted_mestorf
```
If you’ve been following along, you should see several containers listed. These are containers that you started and stopped but haven't removed yet.
Restart the container that you have just stopped. Locate the name of the container and replace the name of the container in the following `restart` command:
```console
$ docker restart inspiring_ishizaka
```
Now, list all the containers again using the `ps` command:
```console
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d75e61fcad1e docker-gs-ping "/docker-gs-ping" 2 minutes ago Up 5 seconds 0.0.0.0:8080->8080/tcp inspiring_ishizaka
f65dbbb9a548 docker-gs-ping "/docker-gs-ping" 4 minutes ago Exited (2) 2 minutes ago wizardly_joliot
aade1bf3d330 docker-gs-ping "/docker-gs-ping" 4 minutes ago Exited (2) 4 minutes ago magical_carson
52d5ce3c15f0 docker-gs-ping "/docker-gs-ping" 10 minutes ago Exited (2) 4 minutes ago gifted_mestorf
```
Notice that the container you just restarted has been started in detached mode and has port `8080` exposed. Also, note that the status of the container is `Up X seconds`. When you restart a container, it will be started with the same flags or commands that it was originally started with.
Stop and remove all of your containers and take a look at fixing the random naming issue.
Stop the container you just started. Find the name of your running container and replace the name in the following command with the name of the container on your system:
```console
$ docker stop inspiring_ishizaka
inspiring_ishizaka
```
Now that all of your containers are stopped, remove them. When a container is removed, it's no longer running nor is it in the stopped state. Instead, the process inside the container is terminated and the metadata for the container is removed.
To remove a container, run the `docker rm` command passing the container name. You can pass multiple container names to the command in one command.
Again, make sure you replace the containers names in the following command with the container names from your system:
```console
$ docker rm inspiring_ishizaka wizardly_joliot magical_carson gifted_mestorf
inspiring_ishizaka
wizardly_joliot
magical_carson
gifted_mestorf
```
Run the `docker ps --all` command again to verify that all containers are gone.
Now, address the pesky random name issue. Standard practice is to name your containers for the simple reason that it's easier to identify what's running in the container and what application or service it's associated with. Just like good naming conventions for variables in your code makes it simpler to read. So goes naming your containers.
To name a container, you must pass the `--name` flag to the `run` command:
```console
$ docker run -d -p 8080:8080 --name rest-server docker-gs-ping
3bbc6a3102ea368c8b966e1878a5ea9b1fc61187afaac1276c41db22e4b7f48f
```
```console
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3bbc6a3102ea docker-gs-ping "/docker-gs-ping" 25 seconds ago Up 24 seconds 0.0.0.0:8080->8080/tcp rest-server
```
Now, you can easily identify your container based on the name.
## Next steps
In this module, you learned how to run containers and publish ports. You also learned to manage the lifecycle of containers. You then learned the importance of naming your containers so that they're more easily identifiable. In the next module, you’ll learn how to run a database in a container and connect it to your application.

Some files were not shown because too many files have changed in this diff Show More