Skip to content

Commit

Permalink
Improvements to Docker builds (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmus authored Feb 16, 2022
1 parent 19de189 commit 5d711a6
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 8 deletions.
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# 0.9-beta

* New: If there is no `.dockerignore` file found when building a `Dockerfile`,
create one with some sensible defaults
* New: By default, Docker builds will compress build context before sending
it to the Docker daemon
* Fixed: Required `RepositoryUrl` parameter for NuGet packages is now
the correct URL for the repository... for real this time

Expand Down
4 changes: 4 additions & 0 deletions Source/Bake/Cooking/Composers/DockerComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,20 @@ public class DockerComposer : Composer
};

private readonly ILogger<DockerComposer> _logger;
private readonly IDefaults _defaults;
private readonly IFileSystem _fileSystem;
private readonly IContainerTagParser _containerTagParser;
private readonly IConventionInterpreter _conventionInterpreter;

public DockerComposer(
ILogger<DockerComposer> logger,
IDefaults defaults,
IFileSystem fileSystem,
IContainerTagParser containerTagParser,
IConventionInterpreter conventionInterpreter)
{
_logger = logger;
_defaults = defaults;
_fileSystem = fileSystem;
_containerTagParser = containerTagParser;
_conventionInterpreter = conventionInterpreter;
Expand Down Expand Up @@ -140,6 +143,7 @@ private IEnumerable<Recipe> CreateRecipes(
path,
slug,
tags,
_defaults.DockerBuildCompress,
new ContainerArtifact(
slug,
tags.ToArray()));
Expand Down
26 changes: 25 additions & 1 deletion Source/Bake/Cooking/Cooks/Docker/DockerBuildCook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,32 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Bake.Services;
using Bake.Services.Tools;
using Bake.Services.Tools.DockerArguments;
using Bake.ValueObjects.Recipes.Docker;
using Microsoft.Extensions.Logging;

// ReSharper disable StringLiteralTypo

namespace Bake.Cooking.Cooks.Docker
{
public class DockerBuildCook : Cook<DockerBuildRecipe>
{
private readonly ILogger<DockerBuildCook> _logger;
private readonly IDockerIgnores _dockerIgnores;
private readonly IDocker _docker;

public DockerBuildCook(
ILogger<DockerBuildCook> logger,
IDockerIgnores dockerIgnores,
IDocker docker)
{
_logger = logger;
_dockerIgnores = dockerIgnores;
_docker = docker;
}

Expand All @@ -43,9 +54,22 @@ protected override async Task<bool> CookAsync(
DockerBuildRecipe recipe,
CancellationToken cancellationToken)
{
var directoryPath = Path.GetDirectoryName(recipe.Path);
var dockerIgnoreFilePath = Path.Join(directoryPath, ".dockerignore");
if (!File.Exists(dockerIgnoreFilePath))
{
_logger.LogWarning(
"There is no '.dockerignore' file at {FilePath}, consider adding one! Bake will create one with some sensible defaults for you",
dockerIgnoreFilePath);
await _dockerIgnores.WriteAsync(
directoryPath,
cancellationToken);
}

var argument = new DockerBuildArgument(
recipe.Path,
recipe.Tags);
recipe.Tags,
recipe.Compress);

using var toolResult = await _docker.BuildAsync(
argument,
Expand Down
4 changes: 4 additions & 0 deletions Source/Bake/Cooking/Cooks/Go/GoDockerFileCook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@ public class GoDockerFileCook : Cook<GoDockerFileRecipe>

private const string Dockerfile = @"
FROM gcr.io/distroless/base-debian10
{{LABELS}}
WORKDIR /
COPY {{SRC}} /{{DST}}
EXPOSE {{PORT}}
USER nonroot:nonroot
ENTRYPOINT [""/{{DST}}""]
";
Expand Down
32 changes: 26 additions & 6 deletions Source/Bake/Core/Defaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

// ReSharper disable StringLiteralTypo

namespace Bake.Core
{
public class Defaults : IDefaults
Expand All @@ -35,6 +38,7 @@ public class Defaults : IDefaults
public string NuGetRegistry { get; private set; } = "https://api.nuget.org/v3/index.json";
public string DockerHubUserRegistry { get; private set; } = "{USER}/";
public string GitHubUserRegistry { get; private set; } = "ghcr.io/{USER}/";
public bool DockerBuildCompress { get; private set; } = true;

public Defaults(
IEnvironmentVariables environmentVariables)
Expand All @@ -47,14 +51,30 @@ public async Task InitializeAsync(
{
var e = await _environmentVariables.GetAsync(cancellationToken);

GitHubUrl = Get(e, "github_url", GitHubUrl);
GitHubNuGetRegistry = Get(e, "github_packages_nuget_url", GitHubNuGetRegistry);
GitHubUserRegistry = Get(e, "github_packages_container_url", GitHubUserRegistry);
NuGetRegistry = Get(e, "nuget_url", NuGetRegistry);
DockerHubUserRegistry = Get(e, "dockerhub_user_url", DockerHubUserRegistry);
GitHubUrl = GetString(e, "github_url", GitHubUrl);
GitHubNuGetRegistry = GetString(e, "github_packages_nuget_url", GitHubNuGetRegistry);
GitHubUserRegistry = GetString(e, "github_packages_container_url", GitHubUserRegistry);
NuGetRegistry = GetString(e, "nuget_url", NuGetRegistry);
DockerHubUserRegistry = GetString(e, "dockerhub_user_url", DockerHubUserRegistry);
DockerBuildCompress = GetBool(e, "docker_build_compress", true);
}

private static bool GetBool(
IReadOnlyDictionary<string, string> environmentVariables,
string name,
bool defaultValue)
{
var value = GetString(environmentVariables, name, defaultValue.ToString());
if (!bool.TryParse(value, out var b))
{
throw new InvalidOperationException(
$"Cannot parse value '{value}' to bool for key '{name}'");
}

return b;
}

private static string Get(
private static string GetString(
IReadOnlyDictionary<string, string> environmentVariables,
string name,
string defaultValue)
Expand Down
2 changes: 2 additions & 0 deletions Source/Bake/Core/IDefaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public interface IDefaults
string DockerHubUserRegistry { get; }
string GitHubUserRegistry { get; }

bool DockerBuildCompress { get; }

Task InitializeAsync(
CancellationToken cancellationToken);
}
Expand Down
1 change: 1 addition & 0 deletions Source/Bake/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public static IServiceCollection AddBake(
.AddTransient<IBakeProjectParser, BakeProjectParser>()
.AddTransient<IDotNetTfmParser, DotNetTfmParser>()
.AddTransient<IDockerLabels, DockerLabels>()
.AddTransient<IDockerIgnores, DockerIgnores>()
.AddTransient<IGitHub, GitHub>()
.AddSingleton<IGitHubClientFactory, GitHubClientFactory>()
.AddTransient<IPlatformParser, PlatformParser>()
Expand Down
130 changes: 130 additions & 0 deletions Source/Bake/Services/DockerIgnores.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// MIT License
//
// Copyright (c) 2021-2022 Rasmus Mikkelsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

// ReSharper disable StringLiteralTypo

namespace Bake.Services
{
public class DockerIgnores : IDockerIgnores
{
private static readonly IReadOnlyCollection<string> Ignores = new[]
{
"# Repository stuff",
"**/*.md",

"# Git",
"**/.git*",

"# GitHub",
"**/.github",

"# Python",
"**/env",
"**/*.pyc",
"**/.cache",
"**/.coverage",
"**/.pytest_cache",

"# .NET",
"**/obj",
"**/*.*proj.user",

"# Java",
"**/.classpath",

"# Docker files",
"**/docker-compose*.yml",
"**/.dockerignore",
"**/Dockerfile*",

"# Mac OS X",
"**/.DS_Store",

"# NodeJS",
"**/node_modules",
"**/.bundleignore",
"**/.bundle",

"# Editors",
"**/.vscode",
"**/.idea",
"**/.vs",

"# Specific files",
"**/Makefile",

"# Build systems",
"**/.gitlab-ci.yml",
"**/.travis.yml",
"**/.drone.yml",

"# Helm",
"**/charts",

"# Others",
"**/.env",
"**/*~",
"**/*.log",
"**/.settings",
"**/.toolstarget",
"**/tmp",
"**/.rspec",
};

private const string FileName = ".dockerignore";

private readonly ILogger<DockerIgnores> _logger;

public DockerIgnores(
ILogger<DockerIgnores> logger)
{
_logger = logger;
}

public async Task WriteAsync(
string directoryPath,
CancellationToken cancellationToken)
{
var dockerIgnoreFilePath = Path.Join(directoryPath, FileName);
if (File.Exists(dockerIgnoreFilePath))
{
_logger.LogInformation(
"There is already a Docker ignore file located at {FilePath}, skipping writing one",
dockerIgnoreFilePath);
return;
}

var content = string.Join(Environment.NewLine, Ignores);
await File.WriteAllTextAsync(
dockerIgnoreFilePath,
content,
cancellationToken);
}
}
}
34 changes: 34 additions & 0 deletions Source/Bake/Services/IDockerIgnores.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// MIT License
//
// Copyright (c) 2021-2022 Rasmus Mikkelsen
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System.Threading;
using System.Threading.Tasks;

namespace Bake.Services
{
public interface IDockerIgnores
{
Task WriteAsync(
string directoryPath,
CancellationToken cancellationToken);
}
}
4 changes: 4 additions & 0 deletions Source/Bake/Services/Tools/Docker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public async Task<IToolResult> BuildAsync(
};
arguments.AddRange(argument.Tags.SelectMany(t => new []{"-t", t}));
arguments.Add(".");
if (argument.Compress)
{
arguments.Add("--compress");
}

var workingDirectory = Path.GetDirectoryName(argument.Path);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ public class DockerBuildArgument : Argument
{
public string Path { get; }
public IReadOnlyCollection<string> Tags { get; }
public bool Compress { get; }

public DockerBuildArgument(
string path,
IReadOnlyCollection<string> tags)
IReadOnlyCollection<string> tags,
bool compress)
{
Path = path;
Tags = tags;
Compress = compress;
}
}
}
Loading

0 comments on commit 5d711a6

Please sign in to comment.