-
Notifications
You must be signed in to change notification settings - Fork 56
feat(issue-1236): enhance docker build with additional build configuration #1284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
74b1b50
fb9994b
a2c383c
ac7b7fa
3d0b8a8
c7acc98
ffd5962
4bfd7fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,6 +91,64 @@ All other fields work the same as CodeZip agents. | |
| > must also add a `Dockerfile` and `.dockerignore` to the agent's code directory. The easiest way is to create a | ||
| > throwaway container agent with `agentcore add agent --build Container` and copy the generated files. | ||
|
|
||
| ### Advanced: Shared Dockerfile (monorepo) | ||
|
|
||
| When multiple agents share the same build logic, you can point them all at a single `Dockerfile` using two optional | ||
| fields: | ||
|
|
||
| | Field | Description | | ||
| | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | ||
| | `buildContextPath` | Docker build context directory. Replaces `codeLocation` as the `docker build` context and as the root the `dockerfile` path is resolved against. | | ||
| | `customDockerBuildArgs` | Key/value pairs forwarded as `--build-arg` flags, allowing a shared Dockerfile to branch per agent. Keys must be valid identifiers. | | ||
|
|
||
| Both fields are honored identically by local `agentcore dev` / `agentcore package` and by `agentcore deploy` (which | ||
| builds in CodeBuild). The `dockerfile` field is resolved relative to the build context, so with `buildContextPath: "."` | ||
| the default `Dockerfile` refers to `./Dockerfile` at the project root. `dockerfile` may also be a relative subpath (e.g. | ||
| `docker/Dockerfile`); absolute paths and `..` traversal are rejected. | ||
|
|
||
| **Example — two agents, one shared `Dockerfile` at the project root:** | ||
|
|
||
| ```json | ||
| { | ||
| "name": "agent-one", | ||
| "build": "Container", | ||
| "entrypoint": "main.py", | ||
| "codeLocation": "app/agent-one/", | ||
| "buildContextPath": ".", | ||
| "customDockerBuildArgs": { "AGENT_NAME": "agent-one" } | ||
| }, | ||
| { | ||
| "name": "agent-two", | ||
| "build": "Container", | ||
| "entrypoint": "main.py", | ||
| "codeLocation": "app/agent-two/", | ||
| "buildContextPath": ".", | ||
| "customDockerBuildArgs": { "AGENT_NAME": "agent-two" } | ||
| } | ||
| ``` | ||
|
|
||
| The shared `Dockerfile` can then branch on the build arg: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tied to the deploy issue: this example will not work end-to-end with |
||
|
|
||
| ```dockerfile | ||
| ARG AGENT_NAME | ||
| COPY app/${AGENT_NAME}/ ./app/ | ||
| ``` | ||
|
|
||
| **When to use `buildContextPath`:** use it when your `Dockerfile` needs to `COPY` files that live outside of | ||
| `codeLocation` (e.g. shared libraries at the project root). Without it, Docker only sees the `codeLocation` directory as | ||
| its build context. | ||
|
|
||
| > **A `.dockerignore` is generated at the build-context root.** When you set `buildContextPath`, the whole of that | ||
| > directory is the build context — for `buildContextPath: "."` that's your entire project. If there's no `.dockerignore` | ||
| > at that root, `agentcore` creates one (excluding `.env`, `.env.*`, `.git/`, `.venv/`, `node_modules/`, `agentcore/`) | ||
| > so secrets and build junk stay out of the image and the CodeBuild upload. It's an ordinary file — commit it, and edit | ||
| > it to include anything you intentionally want in the context (e.g. a non-secret `.env.production`, by removing that | ||
| > line). Both local `agentcore dev` / `agentcore package` and `agentcore deploy` honor the same root `.dockerignore`, so | ||
| > what's excluded locally is exactly what's excluded from the CodeBuild upload. | ||
|
|
||
| **When to use `customDockerBuildArgs`:** use it to parameterise a shared `Dockerfile` so each agent produces a different | ||
| image (different entry point, bundled code, etc.) without duplicating the file. | ||
|
|
||
| ## Local Development | ||
|
|
||
| ```bash | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,11 @@ | ||
| import { ConfigIO, DOCKERFILE_NAME, getDockerfilePath, requireConfigRoot, resolveCodeLocation } from '../../../lib'; | ||
| import { | ||
| ConfigIO, | ||
| DOCKERFILE_NAME, | ||
| ensureBuildContextDockerignore, | ||
| getDockerfilePath, | ||
| requireConfigRoot, | ||
| resolveCodeLocation, | ||
| } from '../../../lib'; | ||
| import { StaleCdkConstructError, ValidationError } from '../../../lib/errors/types'; | ||
| import type { AgentCoreProjectSpec, AwsDeploymentTarget } from '../../../schema'; | ||
| import { validateAwsCredentials } from '../../aws/account'; | ||
|
|
@@ -198,8 +205,10 @@ export function validateContainerAgents(projectSpec: AgentCoreProjectSpec, confi | |
| const errors: string[] = []; | ||
| for (const agent of projectSpec.runtimes || []) { | ||
| if (agent.build === 'Container') { | ||
| const codeLocation = resolveCodeLocation(agent.codeLocation, configRoot); | ||
| const dockerfilePath = getDockerfilePath(codeLocation, agent.dockerfile); | ||
| // Resolve the Dockerfile against the build context (buildContextPath ?? codeLocation), matching | ||
| // how ContainerSourceAsset uploads the context and how the CodeBuild buildspec resolves it. | ||
| const buildContext = resolveCodeLocation(agent.buildContextPath ?? agent.codeLocation, configRoot); | ||
| const dockerfilePath = getDockerfilePath(buildContext, agent.dockerfile); | ||
|
|
||
| if (!existsSync(dockerfilePath)) { | ||
| errors.push( | ||
|
|
@@ -208,6 +217,20 @@ export function validateContainerAgents(projectSpec: AgentCoreProjectSpec, confi | |
| } else { | ||
| warnDeprecatedBaseImage(dockerfilePath, agent.name); | ||
| } | ||
| // buildContextPath widens the docker build context (e.g. the whole repo). Ensure a | ||
| // .dockerignore exists at that root so secrets/junk (.env, .git, agentcore/) are never baked | ||
| // into the image or uploaded to CodeBuild. Both local and deploy honor this same file; it is | ||
| // created only when absent (never overwrites the user's). | ||
| if (agent.buildContextPath) { | ||
| const created = ensureBuildContextDockerignore(buildContext); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocker — correctness] Preflight masks its own friendly error and writes into the repo on a failing deploy.
Note the inconsistency with |
||
| if (created) { | ||
| console.warn( | ||
| `Agent "${agent.name}": created ${created} with default secret exclusions because buildContextPath is ` + | ||
| `set (the entire context is sent to Docker/CodeBuild). Review and commit it; edit to include any ` + | ||
| `intentionally-bundled files.` | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if (errors.length > 0) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Separate issue with this example regardless of the deploy plumbing:
dockerfileis validated as a filename (no path separators — seesrc/schema/schemas/agent-env.tsandgetDockerfilePathinsrc/lib/constants.ts), andgetDockerfilePathjoins it ontocodeLocation. So the implied "single Dockerfile at the project root" setup isn't achievable today — each agent'scodeLocationwould still need its ownDockerfilefile (even if it's just a one-liner that delegates).Either (a) extend
dockerfileto accept a path relative to the build context (and resolve it accordingly), or (b) update this section to clarify that eachcodeLocationmust still contain aDockerfile(which can simply be a thin wrapper / symlink) and adjust the example accordingly.