/// <summary> /// Run a container. Does NOT pull the container - the assumption is that /// the container already exists.. /// </summary> /// <param name="image"></param> /// <param name="entrypoint"></param> /// <param name="args"></param> /// <param name="volumes"></param> /// <param name="environment"></param> /// <param name="workingDir"></param> /// <param name="cancelToken"></param> /// <returns></returns> public async Task RunContainerAsync(string image, string entrypoint, IEnumerable <string> args, IReadOnlyList <Volume> volumes, Dictionary <string, string> environment, string workingDir, CancellationToken cancelToken) { CreateContainerParameters parameters = new CreateContainerParameters() { Image = image, Entrypoint = entrypoint.ToEnumerable().AppendMany(args).ToList(), Env = environment?.Select((x, y) => $"{x}={y}")?.ToList(), Tty = false, HostConfig = new HostConfig() { Binds = volumes.Select(v => $"{v.SourcePath}:{v.DestinationPath}").ToList() }, WorkingDir = workingDir }; // Create the container. CreateContainerResponse container = await client.Containers.CreateContainerAsync(parameters, cancelToken); try { // Report any warnings from the docker daemon. foreach (string warning in container.Warnings) { warningHandler(warning); } // Start the container, and wait for it to exit. await client.Containers.StartContainerAsync(container.ID, new ContainerStartParameters(), cancelToken); // Watch stdout and/or stderr as necessary. Task stdoutListener = WatchStdoutStreamAsync(container.ID, cancelToken); Task stderrListener = WatchStderrStreamAsync(container.ID, cancelToken); // Wait for the container to exit. ContainerWaitResponse waitResponse = await client.Containers.WaitContainerAsync(container.ID, cancelToken); // Wait for output listeners if cancellation has not been requested. if (!cancelToken.IsCancellationRequested) { await stdoutListener.ConfigureAwait(false); await stderrListener.ConfigureAwait(false); } // If cancellation isn't requested, ensure the container exited gracefully. if (!cancelToken.IsCancellationRequested && waitResponse.StatusCode != 0) { (string stdout, string stderr) = await GetContainerLogsAsync(container.ID, parameters.Tty, cancelToken); StringBuilder output = new StringBuilder(); output.AppendLine(stdout); output.AppendLine(stderr); throw new Exception($"Container exited with non-zero exit code. Container log:\n{output}"); } } finally { ContainerRemoveParameters removeParameters = new ContainerRemoveParameters() { RemoveVolumes = true, Force = true }; ContainerKillParameters killParameters = new ContainerKillParameters() { }; // Only attempt to kill the container if it's still running. if (await IsRunning(container.ID)) { await client.Containers.KillContainerAsync(container.ID, killParameters); } await client.Containers.RemoveContainerAsync(container.ID, removeParameters); } }
public async Task WaitOnServerExit(string containerId) { ContainerWaitResponse containerWaitResponse = await _dockerClient.Containers.WaitContainerAsync(containerId).ConfigureAwait(false); _logger.LogInformation($"Container {containerId} exited with exit code {containerWaitResponse.StatusCode}."); }