Skip to content
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

Allow more customization of docker run command #690

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 57 additions & 1 deletion README.md
Expand Up @@ -228,6 +228,23 @@ Customize the Docker container run process by adding properties under the `docke
| `env` | Environment variables applied to the container. | None |
| `envFiles` | Files of environment variables read in and applied to the container. Environment variables are specified one per line, in `<name>=<value>` format. | None |
| `labels` | The set of labels added to the container. | `com.microsoft.created-by` = `visual-studio-code` |
| `ports` | Ports that are going to be mapped on the host. | All ports exposed by the Dockerfile will be bound to a random port on the host machine |
| `extraHosts` | Hosts to be added to the container's `hosts` file for DNS resolution. | None |
| `volumes` | Volumes that are going to be mapped to the container. | None |

# ports
| Property | Description | Required | Default |
| --- | --- | --- | --- |
| `hostPort` | Port number to be bound on the host. | No | None |
| `containerPort` | Port number of the container to be bound. | Yes | None |
| `protocol` | Specific protocol for the binding (`tcp | udp`). If no protocol is specified it will bind both. | No | None |

# volumes
| Property | Description | Required | Default |
| --- | --- | --- | --- |
| `localPath` | Path on local machine that will be mapped. The folder will be created if it does not exist. | Yes | None |
| `containerPath` | Path where the volume will be mapped within the container. The folder will be created if it does not exist. | Yes | None |
| `permissions` | Permissions for the container for the mapped volume, `rw` for read-write or `ro` for read-only. | Yes | `rw` |

Example run customization:

Expand All @@ -251,7 +268,46 @@ Example run customization:
"labels": {
"label1": "value1",
"label2": "value2"
}
},
"ports": [
philliphoff marked this conversation as resolved.
Show resolved Hide resolved
{
"hostPort": 80,
"containerPort": 80
},
{
"containerPort": 443
},
{
"containerPort": 6029,
"protocol": "udp"
},
{
"containerPort": 6029,
"protocol": "tcp"
},
{
"hostPort": 4562,
"containerPort": 5837,
"protocol": "tcp"
}
],
"extraHosts": [
{
"hostname": "some-hostname",
"ip": "some-ip"
},
{
"hostname": "some-other-hostname",
"ip": "some-other-ip"
}
],
"volumes": [
{
"localPath": "path-on-host-machine",
"containerPath": "path-inside-container",
"permissions": "ro|rw"
}
]
}
}
]
Expand Down
18 changes: 17 additions & 1 deletion debugging/coreclr/dockerClient.ts
Expand Up @@ -27,6 +27,17 @@ export type DockerContainerRemoveOptions = {
force?: boolean;
};

export type DockerContainerPort = {
hostPort?: string;
containerPort: string;
protocol?: 'tcp' | 'udp';
}

export type DockerContainerExtraHost = {
hostname: string;
ip: string;
}

export type DockerContainerVolume = {
localPath: string;
containerPath: string;
Expand All @@ -41,6 +52,8 @@ export type DockerRunContainerOptions = {
envFiles?: string[];
labels?: { [key: string]: string };
volumes?: DockerContainerVolume[];
ports?: DockerContainerPort[];
extraHosts?: DockerContainerExtraHost[];
};

export type DockerVersionOptions = {
Expand Down Expand Up @@ -187,12 +200,15 @@ export class CliDockerClient implements DockerClient {
options = options || {};

const command = CommandLineBuilder
.create('docker', 'run', '-dt', '-P')
.create('docker', 'run', '-dt')
.withFlagArg('-P', options.ports === undefined || options.ports.length < 1)
.withNamedArg('--name', options.containerName)
.withKeyValueArgs('-e', options.env)
.withArrayArgs('--env-file', options.envFiles)
.withKeyValueArgs('--label', options.labels)
.withArrayArgs('-v', options.volumes, volume => `${volume.localPath}:${volume.containerPath}${volume.permissions ? ':' + volume.permissions : ''}`)
.withArrayArgs('-p', options.ports, port => `${port.hostPort ? port.hostPort + ':' : ''}${port.containerPort}${port.protocol ? '/' + port.protocol : ''}`)
.withArrayArgs('--add-host', options.extraHosts, extraHost => `${extraHost.hostname}:${extraHost.ip}`)
.withNamedArg('--entrypoint', options.entrypoint)
.withQuotedArg(imageTagOrId)
.withArg(options.command)
Expand Down
11 changes: 11 additions & 0 deletions debugging/coreclr/dockerDebugConfigurationProvider.ts
Expand Up @@ -7,6 +7,7 @@ import { CancellationToken, DebugConfiguration, DebugConfigurationProvider, Prov
import { callWithTelemetryAndErrorHandling } from 'vscode-azureextensionui';
import { PlatformOS } from '../../utils/platform';
import { DebugSessionManager } from './debugSessionManager';
import { DockerContainerExtraHost, DockerContainerPort, DockerContainerVolume } from './dockerClient';
import { DockerManager, LaunchBuildOptions, LaunchResult, LaunchRunOptions } from './dockerManager';
import { FileSystemProvider } from './fsProvider';
import { NetCoreProjectProvider } from './netCoreProjectProvider';
Expand All @@ -28,6 +29,9 @@ interface DockerDebugRunOptions {
envFiles?: string[];
labels?: { [key: string]: string };
os?: PlatformOS;
ports?: DockerContainerPort[];
volumes?: DockerContainerVolume[];
extraHosts?: DockerContainerExtraHost[];
}

interface DebugConfigurationBrowserBaseOptions {
Expand Down Expand Up @@ -179,12 +183,19 @@ export class DockerDebugConfigurationProvider implements DebugConfigurationProvi
const labels = (debugConfiguration && debugConfiguration.dockerRun && debugConfiguration.dockerRun.labels)
|| DockerDebugConfigurationProvider.defaultLabels;

const ports = debugConfiguration && debugConfiguration.dockerRun && debugConfiguration.dockerRun.ports;
const volumes = debugConfiguration && debugConfiguration.dockerRun && debugConfiguration.dockerRun.volumes;
const extraHosts = debugConfiguration && debugConfiguration.dockerRun && debugConfiguration.dockerRun.extraHosts;

return {
containerName,
env,
envFiles,
extraHosts,
labels,
os,
ports,
volumes
};
}

Expand Down
4 changes: 3 additions & 1 deletion debugging/coreclr/dockerManager.ts
Expand Up @@ -216,8 +216,10 @@ export class DefaultDockerManager implements DockerManager {
entrypoint,
env: options.env,
envFiles: options.envFiles,
extraHosts: options.extraHosts,
labels: options.labels,
volumes
ports: options.ports,
volumes: [...volumes, ...options.volumes]
philliphoff marked this conversation as resolved.
Show resolved Hide resolved
});
},
id => `Container ${this.dockerClient.trimId(id)} started.`,
Expand Down
78 changes: 78 additions & 0 deletions package.json
Expand Up @@ -407,6 +407,84 @@
"additionalProperties": {
"type": "string"
}
},
"ports": {
"type": "array",
"description": "Ports that are going to be mapped on the host.",
"items": {
"type": "object",
"properties": {
"hostPort": {
"type": "string",
"description": "Port number to be bound on the host."
},
"containerPort": {
"type": "string",
"description": "Port number of the container to be bound."
},
"protocol": {
"type": "string",
"description": "Specific protocol for the binding (`tcp | udp`).",
"enum": [
"tcp",
"udp"
]
},
"required": [
"containerPort"
]
}
}
},
"extraHosts": {
"type": "array",
"description": "Hosts to be added to the container's `hosts` file for DNS resolution.",
"items": {
"type": "object",
"properties": {
"hostname": {
"type": "string",
"description": "Hostname for dns resolution."
},
"ip": {
"type": "string",
"description": "IP associated to the hostname."
}
},
"required": [
"hostname",
"ip"
]
}
},
"volumes": {
"type": "array",
"description": "Volumes that are going to be mapped to the container.",
"items": {
"type": "object",
"properties": {
"localPath": {
"type": "string",
"description": "Path on local machine that will be mapped. The folder will be created if it does not exist."
},
"containerPath": {
"type": "string",
"description": "Path where the volume will be mapped within the container. The folder will be created if it does not exist."
},
"permissions": {
"type": "string",
"description": "Permissions for the container for the mapped volume, `rw` for read-write or `ro` for read-only.",
"enum": [
"rw",
"ro"
]
}
},
"required": [
"localPath",
"containerPath"
]
}
}
}
}
Expand Down