From 418b8308d366e35445fdbabcee35072a398d8e81 Mon Sep 17 00:00:00 2001 From: MunsMan Date: Wed, 1 Mar 2023 17:58:34 +0000 Subject: [PATCH 1/7] adding 'static' port forwarding support - agilgur5 modification: rebased with `main` --- src/spec-node/containerNetwork.ts | 24 ++++++++++++++++++++++++ src/spec-node/singleContainer.ts | 7 +++---- 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 src/spec-node/containerNetwork.ts diff --git a/src/spec-node/containerNetwork.ts b/src/spec-node/containerNetwork.ts new file mode 100644 index 000000000..6d1173dff --- /dev/null +++ b/src/spec-node/containerNetwork.ts @@ -0,0 +1,24 @@ +import { DevContainerConfig, DevContainerFromDockerfileConfig, DevContainerFromImageConfig } from '../spec-configuration/configuration'; + +function getStaticPorts (ports: number | string | (number | string)[] | undefined): string[]{ + ports = ports ?? []; + ports = typeof ports === 'number' || typeof ports === 'string'? [ports] : ports; + return ports.map((port) => typeof port === 'number'? `127.0.0.1:${port}:${port}`: port); +} + +function appPorts (config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[]{ + return getStaticPorts(config.appPort); +} + +function hasAppPorts(obj: unknown):obj is (DevContainerFromDockerfileConfig | DevContainerFromImageConfig) { + return (obj as DevContainerFromDockerfileConfig | DevContainerFromImageConfig).appPort !== undefined; +} +export function applyStaticPorts (config: DevContainerConfig): string[] { + let staticPorts: string[] = []; + staticPorts = staticPorts.concat(...getStaticPorts(config.forwardPorts)); + if(hasAppPorts(config)){ + staticPorts = staticPorts.concat(...appPorts(config)); + } + return ([]).concat(...staticPorts.map((port) => ['-p', port])); +} + diff --git a/src/spec-node/singleContainer.ts b/src/spec-node/singleContainer.ts index 9b0783443..64e6ac133 100644 --- a/src/spec-node/singleContainer.ts +++ b/src/spec-node/singleContainer.ts @@ -13,6 +13,7 @@ import { LogLevel, Log, makeLog } from '../spec-utils/log'; import { extendImage, getExtendImageBuildInfo, updateRemoteUserUID } from './containerFeatures'; import { getDevcontainerMetadata, getImageBuildInfoFromDockerfile, getImageMetadataFromContainer, ImageMetadataEntry, lifecycleCommandOriginMapFromMetadata, mergeConfiguration, MergedDevContainerConfig } from './imageMetadata'; import { ensureDockerfileHasFinalStageName, generateMountCommand } from './dockerfileUtils'; +import { applyStaticPorts } from './containerNetwork'; export const hostFolderLabel = 'devcontainer.local_folder'; // used to label containers created from a workspace/folder export const configFileLabel = 'devcontainer.config_file'; @@ -196,7 +197,7 @@ async function buildAndExtendImage(buildParams: DockerResolverParameters, config if (buildParams.buildxPush) { args.push('--push'); } else { - if (buildParams.buildxOutput) { + if (buildParams.buildxOutput) { args.push('--output', buildParams.buildxOutput); } else { args.push('--load'); // (short for --output=docker, i.e. load into normal 'docker images' collection) @@ -348,9 +349,7 @@ export async function spawnDevContainer(params: DockerResolverParameters, config const { common } = params; common.progress(ResolverProgress.StartingContainer); - const appPort = config.appPort; - const exposedPorts = typeof appPort === 'number' || typeof appPort === 'string' ? [appPort] : appPort || []; - const exposed = ([]).concat(...exposedPorts.map(port => ['-p', typeof port === 'number' ? `127.0.0.1:${port}:${port}` : port])); + const exposed = applyStaticPorts(config); const cwdMount = workspaceMount ? ['--mount', workspaceMount] : []; From 3cf9c34db7953341d0b3736a9b2611c5e6bc6536 Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Mon, 15 Jul 2024 23:24:09 -0400 Subject: [PATCH 2/7] rename file to `ports.ts` - it doesn't cover all networking at this time Signed-off-by: Anton Gilgur --- src/spec-node/{containerNetwork.ts => ports.ts} | 0 src/spec-node/singleContainer.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/spec-node/{containerNetwork.ts => ports.ts} (100%) diff --git a/src/spec-node/containerNetwork.ts b/src/spec-node/ports.ts similarity index 100% rename from src/spec-node/containerNetwork.ts rename to src/spec-node/ports.ts diff --git a/src/spec-node/singleContainer.ts b/src/spec-node/singleContainer.ts index 64e6ac133..a7080f899 100644 --- a/src/spec-node/singleContainer.ts +++ b/src/spec-node/singleContainer.ts @@ -13,7 +13,7 @@ import { LogLevel, Log, makeLog } from '../spec-utils/log'; import { extendImage, getExtendImageBuildInfo, updateRemoteUserUID } from './containerFeatures'; import { getDevcontainerMetadata, getImageBuildInfoFromDockerfile, getImageMetadataFromContainer, ImageMetadataEntry, lifecycleCommandOriginMapFromMetadata, mergeConfiguration, MergedDevContainerConfig } from './imageMetadata'; import { ensureDockerfileHasFinalStageName, generateMountCommand } from './dockerfileUtils'; -import { applyStaticPorts } from './containerNetwork'; +import { applyStaticPorts } from './ports'; export const hostFolderLabel = 'devcontainer.local_folder'; // used to label containers created from a workspace/folder export const configFileLabel = 'devcontainer.config_file'; From 666d52b468c8c536897f1cec1aeb239a407ff15a Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Mon, 15 Jul 2024 23:36:13 -0400 Subject: [PATCH 3/7] simplify and fix naming and style Signed-off-by: Anton Gilgur --- src/spec-node/ports.ts | 23 ++++++----------------- src/spec-node/singleContainer.ts | 4 ++-- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/spec-node/ports.ts b/src/spec-node/ports.ts index 6d1173dff..d1496e25b 100644 --- a/src/spec-node/ports.ts +++ b/src/spec-node/ports.ts @@ -1,24 +1,13 @@ -import { DevContainerConfig, DevContainerFromDockerfileConfig, DevContainerFromImageConfig } from '../spec-configuration/configuration'; +import { DevContainerFromDockerfileConfig, DevContainerFromImageConfig } from '../spec-configuration/configuration'; -function getStaticPorts (ports: number | string | (number | string)[] | undefined): string[]{ +function normalizePorts(ports: number | string | (number | string)[] | undefined): string[]{ ports = ports ?? []; ports = typeof ports === 'number' || typeof ports === 'string'? [ports] : ports; - return ports.map((port) => typeof port === 'number'? `127.0.0.1:${port}:${port}`: port); + return ports.map((port) => typeof port === 'number' ? `127.0.0.1:${port}:${port}`: port); } -function appPorts (config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[]{ - return getStaticPorts(config.appPort); -} - -function hasAppPorts(obj: unknown):obj is (DevContainerFromDockerfileConfig | DevContainerFromImageConfig) { - return (obj as DevContainerFromDockerfileConfig | DevContainerFromImageConfig).appPort !== undefined; -} -export function applyStaticPorts (config: DevContainerConfig): string[] { - let staticPorts: string[] = []; - staticPorts = staticPorts.concat(...getStaticPorts(config.forwardPorts)); - if(hasAppPorts(config)){ - staticPorts = staticPorts.concat(...appPorts(config)); - } - return ([]).concat(...staticPorts.map((port) => ['-p', port])); +export function getStaticPorts(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[] { + const staticPorts = normalizePorts(config.forwardPorts).concat(normalizePorts(config.appPort)); + return staticPorts.flatMap((port) => ['-p', port]); } diff --git a/src/spec-node/singleContainer.ts b/src/spec-node/singleContainer.ts index a7080f899..82702e207 100644 --- a/src/spec-node/singleContainer.ts +++ b/src/spec-node/singleContainer.ts @@ -13,7 +13,7 @@ import { LogLevel, Log, makeLog } from '../spec-utils/log'; import { extendImage, getExtendImageBuildInfo, updateRemoteUserUID } from './containerFeatures'; import { getDevcontainerMetadata, getImageBuildInfoFromDockerfile, getImageMetadataFromContainer, ImageMetadataEntry, lifecycleCommandOriginMapFromMetadata, mergeConfiguration, MergedDevContainerConfig } from './imageMetadata'; import { ensureDockerfileHasFinalStageName, generateMountCommand } from './dockerfileUtils'; -import { applyStaticPorts } from './ports'; +import { getStaticPorts } from './ports'; export const hostFolderLabel = 'devcontainer.local_folder'; // used to label containers created from a workspace/folder export const configFileLabel = 'devcontainer.config_file'; @@ -349,7 +349,7 @@ export async function spawnDevContainer(params: DockerResolverParameters, config const { common } = params; common.progress(ResolverProgress.StartingContainer); - const exposed = applyStaticPorts(config); + const exposed = getStaticPorts(config); const cwdMount = workspaceMount ? ['--mount', workspaceMount] : []; From 214dd2f98de65cd7452af593c85ca571fb71137c Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Mon, 15 Jul 2024 23:40:00 -0400 Subject: [PATCH 4/7] remove second trailing newline Signed-off-by: Anton Gilgur --- src/spec-node/ports.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/spec-node/ports.ts b/src/spec-node/ports.ts index d1496e25b..bdc1d061e 100644 --- a/src/spec-node/ports.ts +++ b/src/spec-node/ports.ts @@ -10,4 +10,3 @@ export function getStaticPorts(config: DevContainerFromDockerfileConfig | DevCon const staticPorts = normalizePorts(config.forwardPorts).concat(normalizePorts(config.appPort)); return staticPorts.flatMap((port) => ['-p', port]); } - From 527f6f14db66e238ff111324932d9cf158e9e3ea Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Mon, 15 Jul 2024 23:44:05 -0400 Subject: [PATCH 5/7] more style fixes and naming Signed-off-by: Anton Gilgur --- src/spec-node/ports.ts | 6 +++--- src/spec-node/singleContainer.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spec-node/ports.ts b/src/spec-node/ports.ts index bdc1d061e..f6b6defca 100644 --- a/src/spec-node/ports.ts +++ b/src/spec-node/ports.ts @@ -1,12 +1,12 @@ import { DevContainerFromDockerfileConfig, DevContainerFromImageConfig } from '../spec-configuration/configuration'; -function normalizePorts(ports: number | string | (number | string)[] | undefined): string[]{ +function normalizePorts(ports: number | string | (number | string)[] | undefined): string[] { ports = ports ?? []; - ports = typeof ports === 'number' || typeof ports === 'string'? [ports] : ports; + ports = typeof ports === 'number' || typeof ports === 'string' ? [ports] : ports; return ports.map((port) => typeof port === 'number' ? `127.0.0.1:${port}:${port}`: port); } -export function getStaticPorts(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[] { +export function getStaticPortsArgs(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[] { const staticPorts = normalizePorts(config.forwardPorts).concat(normalizePorts(config.appPort)); return staticPorts.flatMap((port) => ['-p', port]); } diff --git a/src/spec-node/singleContainer.ts b/src/spec-node/singleContainer.ts index 82702e207..56505dae8 100644 --- a/src/spec-node/singleContainer.ts +++ b/src/spec-node/singleContainer.ts @@ -13,7 +13,7 @@ import { LogLevel, Log, makeLog } from '../spec-utils/log'; import { extendImage, getExtendImageBuildInfo, updateRemoteUserUID } from './containerFeatures'; import { getDevcontainerMetadata, getImageBuildInfoFromDockerfile, getImageMetadataFromContainer, ImageMetadataEntry, lifecycleCommandOriginMapFromMetadata, mergeConfiguration, MergedDevContainerConfig } from './imageMetadata'; import { ensureDockerfileHasFinalStageName, generateMountCommand } from './dockerfileUtils'; -import { getStaticPorts } from './ports'; +import { getStaticPortsArgs } from './ports'; export const hostFolderLabel = 'devcontainer.local_folder'; // used to label containers created from a workspace/folder export const configFileLabel = 'devcontainer.config_file'; @@ -349,7 +349,7 @@ export async function spawnDevContainer(params: DockerResolverParameters, config const { common } = params; common.progress(ResolverProgress.StartingContainer); - const exposed = getStaticPorts(config); + const exposed = getStaticPortsArgs(config); const cwdMount = workspaceMount ? ['--mount', workspaceMount] : []; From d0df3bbb96d01c94c08674e7ecf271eb086b825e Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Mon, 15 Jul 2024 23:53:13 -0400 Subject: [PATCH 6/7] more cleanly separate out getting ports from converting them into flags Signed-off-by: Anton Gilgur --- src/spec-node/ports.ts | 5 ++--- src/spec-node/singleContainer.ts | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/spec-node/ports.ts b/src/spec-node/ports.ts index f6b6defca..3cc0f2470 100644 --- a/src/spec-node/ports.ts +++ b/src/spec-node/ports.ts @@ -6,7 +6,6 @@ function normalizePorts(ports: number | string | (number | string)[] | undefined return ports.map((port) => typeof port === 'number' ? `127.0.0.1:${port}:${port}`: port); } -export function getStaticPortsArgs(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[] { - const staticPorts = normalizePorts(config.forwardPorts).concat(normalizePorts(config.appPort)); - return staticPorts.flatMap((port) => ['-p', port]); +export function getStaticPorts(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[] { + return normalizePorts(config.forwardPorts).concat(normalizePorts(config.appPort)); } diff --git a/src/spec-node/singleContainer.ts b/src/spec-node/singleContainer.ts index 56505dae8..0cfdf2145 100644 --- a/src/spec-node/singleContainer.ts +++ b/src/spec-node/singleContainer.ts @@ -13,7 +13,7 @@ import { LogLevel, Log, makeLog } from '../spec-utils/log'; import { extendImage, getExtendImageBuildInfo, updateRemoteUserUID } from './containerFeatures'; import { getDevcontainerMetadata, getImageBuildInfoFromDockerfile, getImageMetadataFromContainer, ImageMetadataEntry, lifecycleCommandOriginMapFromMetadata, mergeConfiguration, MergedDevContainerConfig } from './imageMetadata'; import { ensureDockerfileHasFinalStageName, generateMountCommand } from './dockerfileUtils'; -import { getStaticPortsArgs } from './ports'; +import { getStaticPorts } from './ports'; export const hostFolderLabel = 'devcontainer.local_folder'; // used to label containers created from a workspace/folder export const configFileLabel = 'devcontainer.config_file'; @@ -349,7 +349,8 @@ export async function spawnDevContainer(params: DockerResolverParameters, config const { common } = params; common.progress(ResolverProgress.StartingContainer); - const exposed = getStaticPortsArgs(config); + const exposedPorts = getStaticPorts(config); + const exposed = exposedPorts.flatMap((port) => ['-p', port]); const cwdMount = workspaceMount ? ['--mount', workspaceMount] : []; From ae893d9bd934b39019af17eae98e8f6440d68d03 Mon Sep 17 00:00:00 2001 From: Anton Gilgur Date: Thu, 16 Jan 2025 16:40:20 -0500 Subject: [PATCH 7/7] add `--skip-forward-ports` flag to disable this - per review comments, GH Codespaces and VS Code extension use their own implementation for `forwardPorts` and so would conflict with Docker publishing - so `--skip-forward-ports` allows for publishing of `forwardPorts` to be skipped by the CLI NOTE: passing `skipForwardPorts` around required drilling down through a lot of function arguments -- those could potentially be refactored, but that is out-of-scope for now --- src/spec-node/configContainer.ts | 8 ++++---- src/spec-node/devContainers.ts | 3 ++- src/spec-node/devContainersSpecCLI.ts | 5 ++++- src/spec-node/ports.ts | 5 +++-- src/spec-node/singleContainer.ts | 8 ++++---- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/spec-node/configContainer.ts b/src/spec-node/configContainer.ts index ee6b93cb3..f33623ddf 100644 --- a/src/spec-node/configContainer.ts +++ b/src/spec-node/configContainer.ts @@ -23,19 +23,19 @@ import { DockerCLIParameters } from '../spec-shutdown/dockerUtils'; import { createDocuments } from '../spec-configuration/editableFiles'; -export async function resolve(params: DockerResolverParameters, configFile: URI | undefined, overrideConfigFile: URI | undefined, providedIdLabels: string[] | undefined, additionalFeatures: Record>): Promise { +export async function resolve(params: DockerResolverParameters, configFile: URI | undefined, overrideConfigFile: URI | undefined, providedIdLabels: string[] | undefined, additionalFeatures: Record>, skipForwardPorts: boolean): Promise { if (configFile && !/\/\.?devcontainer\.json$/.test(configFile.path)) { throw new Error(`Filename must be devcontainer.json or .devcontainer.json (${uriToFsPath(configFile, params.common.cliHost.platform)}).`); } const parsedAuthority = params.parsedAuthority; if (!parsedAuthority || isDevContainerAuthority(parsedAuthority)) { - return resolveWithLocalFolder(params, parsedAuthority, configFile, overrideConfigFile, providedIdLabels, additionalFeatures); + return resolveWithLocalFolder(params, parsedAuthority, configFile, overrideConfigFile, providedIdLabels, additionalFeatures, skipForwardPorts); } else { throw new Error(`Unexpected authority: ${JSON.stringify(parsedAuthority)}`); } } -async function resolveWithLocalFolder(params: DockerResolverParameters, parsedAuthority: DevContainerAuthority | undefined, configFile: URI | undefined, overrideConfigFile: URI | undefined, providedIdLabels: string[] | undefined, additionalFeatures: Record>): Promise { +async function resolveWithLocalFolder(params: DockerResolverParameters, parsedAuthority: DevContainerAuthority | undefined, configFile: URI | undefined, overrideConfigFile: URI | undefined, providedIdLabels: string[] | undefined, additionalFeatures: Record>, skipForwardPorts: boolean): Promise { const { common, workspaceMountConsistencyDefault } = params; const { cliHost, output } = common; @@ -67,7 +67,7 @@ async function resolveWithLocalFolder(params: DockerResolverParameters, parsedAu let result: ResolverResult; if (isDockerFileConfig(config) || 'image' in config) { - result = await openDockerfileDevContainer(params, configWithRaw as SubstitutedConfig, configs.workspaceConfig, idLabels, additionalFeatures); + result = await openDockerfileDevContainer(params, configWithRaw as SubstitutedConfig, configs.workspaceConfig, idLabels, additionalFeatures, skipForwardPorts); } else if ('dockerComposeFile' in config) { if (!workspace) { throw new ContainerError({ description: `A Dev Container using Docker Compose requires a workspace folder.` }); diff --git a/src/spec-node/devContainers.ts b/src/spec-node/devContainers.ts index 493d0dc22..4046919a1 100644 --- a/src/spec-node/devContainers.ts +++ b/src/spec-node/devContainers.ts @@ -58,6 +58,7 @@ export interface ProvisionOptions { buildxCacheTo: string | undefined; additionalFeatures?: Record>; skipFeatureAutoMapping: boolean; + skipForwardPorts: boolean; skipPostAttach: boolean; containerSessionDataFolder?: string; skipPersistingCustomizationsFromFeatures: boolean; @@ -81,7 +82,7 @@ export async function launch(options: ProvisionOptions, providedIdLabels: string const text = 'Resolving Remote'; const start = output.start(text); - const result = await resolve(params, options.configFile, options.overrideConfigFile, providedIdLabels, options.additionalFeatures ?? {}); + const result = await resolve(params, options.configFile, options.overrideConfigFile, providedIdLabels, options.additionalFeatures ?? {}, options.skipForwardPorts); output.stop(text, start); const { dockerContainerId, composeProjectName } = result; return { diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 59136695d..03f800685 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -130,6 +130,7 @@ function provisionOptions(y: Argv) { 'buildkit': { choices: ['auto' as 'auto', 'never' as 'never'], default: 'auto' as 'auto', description: 'Control whether BuildKit should be used' }, 'additional-features': { type: 'string', description: 'Additional features to apply to the dev container (JSON as per "features" section in devcontainer.json)' }, 'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' }, + 'skip-forward-ports': { type: 'boolean', default: false, description: 'Do not publish forwardPorts.' }, 'skip-post-attach': { type: 'boolean', default: false, description: 'Do not run postAttachCommand.' }, 'dotfiles-repository': { type: 'string', description: 'URL of a dotfiles Git repository (e.g., https://github.com/owner/repository.git)' }, 'dotfiles-install-command': { type: 'string', description: 'The command to run after cloning the dotfiles repository. Defaults to run the first file of `install.sh`, `install`, `bootstrap.sh`, `bootstrap`, `setup.sh` and `setup` found in the dotfiles repository`s root folder.' }, @@ -204,6 +205,7 @@ async function provision({ 'buildkit': buildkit, 'additional-features': additionalFeaturesJson, 'skip-feature-auto-mapping': skipFeatureAutoMapping, + 'skip-forward-ports': skipForwardPorts, 'skip-post-attach': skipPostAttach, 'dotfiles-repository': dotfilesRepository, 'dotfiles-install-command': dotfilesInstallCommand, @@ -277,6 +279,7 @@ async function provision({ buildxCacheTo: addCacheTo, additionalFeatures, skipFeatureAutoMapping, + skipForwardPorts, skipPostAttach, containerSessionDataFolder, skipPersistingCustomizationsFromFeatures: false, @@ -680,7 +683,7 @@ async function doBuild({ if (envFile) { composeGlobalArgs.push('--env-file', envFile); } - + const composeConfig = await readDockerComposeConfig(buildParams, composeFiles, envFile); const projectName = await getProjectName(params, workspace, composeFiles, composeConfig); const services = Object.keys(composeConfig.services || {}); diff --git a/src/spec-node/ports.ts b/src/spec-node/ports.ts index 3cc0f2470..a92e52419 100644 --- a/src/spec-node/ports.ts +++ b/src/spec-node/ports.ts @@ -6,6 +6,7 @@ function normalizePorts(ports: number | string | (number | string)[] | undefined return ports.map((port) => typeof port === 'number' ? `127.0.0.1:${port}:${port}`: port); } -export function getStaticPorts(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig): string[] { - return normalizePorts(config.forwardPorts).concat(normalizePorts(config.appPort)); +export function getStaticPorts(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig, skipForwardPorts: boolean): string[] { + const forwardPorts = skipForwardPorts ? undefined : config.forwardPorts; + return normalizePorts(forwardPorts).concat(normalizePorts(config.appPort)); } diff --git a/src/spec-node/singleContainer.ts b/src/spec-node/singleContainer.ts index 0cfdf2145..7596df31a 100644 --- a/src/spec-node/singleContainer.ts +++ b/src/spec-node/singleContainer.ts @@ -18,7 +18,7 @@ import { getStaticPorts } from './ports'; export const hostFolderLabel = 'devcontainer.local_folder'; // used to label containers created from a workspace/folder export const configFileLabel = 'devcontainer.config_file'; -export async function openDockerfileDevContainer(params: DockerResolverParameters, configWithRaw: SubstitutedConfig, workspaceConfig: WorkspaceConfiguration, idLabels: string[], additionalFeatures: Record>): Promise { +export async function openDockerfileDevContainer(params: DockerResolverParameters, configWithRaw: SubstitutedConfig, workspaceConfig: WorkspaceConfiguration, idLabels: string[], additionalFeatures: Record>, skipForwardPorts: boolean): Promise { const { common } = params; const { config } = configWithRaw; // let collapsedFeaturesConfig: () => Promise; @@ -52,7 +52,7 @@ export async function openDockerfileDevContainer(params: DockerResolverParameter // collapsedFeaturesConfig = async () => res.collapsedFeaturesConfig; try { - await spawnDevContainer(params, config, mergedConfig, updatedImageName, idLabels, workspaceConfig.workspaceMount, res.imageDetails, containerUser, res.labels || {}); + await spawnDevContainer(params, config, mergedConfig, updatedImageName, idLabels, workspaceConfig.workspaceMount, res.imageDetails, containerUser, res.labels || {}, skipForwardPorts); } finally { // In 'finally' because 'docker run' can fail after creating the container. // Trying to get it here, so we can offer 'Rebuild Container' as an action later. @@ -345,11 +345,11 @@ export async function extraRunArgs(common: ResolverParameters, params: DockerRes return extraArguments; } -export async function spawnDevContainer(params: DockerResolverParameters, config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig, mergedConfig: MergedDevContainerConfig, imageName: string, labels: string[], workspaceMount: string | undefined, imageDetails: (() => Promise) | undefined, containerUser: string | undefined, extraLabels: Record) { +export async function spawnDevContainer(params: DockerResolverParameters, config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig, mergedConfig: MergedDevContainerConfig, imageName: string, labels: string[], workspaceMount: string | undefined, imageDetails: (() => Promise) | undefined, containerUser: string | undefined, extraLabels: Record, skipForwardPorts: boolean) { const { common } = params; common.progress(ResolverProgress.StartingContainer); - const exposedPorts = getStaticPorts(config); + const exposedPorts = getStaticPorts(config, skipForwardPorts); const exposed = exposedPorts.flatMap((port) => ['-p', port]); const cwdMount = workspaceMount ? ['--mount', workspaceMount] : [];