Skip to content

Commit

Permalink
solidify registry support, generate secrets at installation instead o…
Browse files Browse the repository at this point in the history
…f bundling in package
  • Loading branch information
tinyzimmer committed Dec 23, 2020
1 parent 28a0970 commit cefdab2
Show file tree
Hide file tree
Showing 13 changed files with 496 additions and 346 deletions.
4 changes: 2 additions & 2 deletions examples/whoami/whoami.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ spec:
spec:
containers:
- name: whoami
image: "traefik/whoami:latest"
imagePullPolicy: Never
image: traefik/whoami:latest
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
Expand Down
39 changes: 20 additions & 19 deletions pkg/build/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ func (b *builder) Build(opts *types.BuildOptions) error {
log.Info("Latest k3s version is", opts.K3sVersion)
}

imageFormat := types.ImageBundleTar
if opts.CreateRegistry {
imageFormat = types.ImageBundleRegistry
}
packageMeta := types.PackageMeta{
MetaVersion: "v1",
Name: opts.Name,
Version: opts.BuildVersion,
K3sVersion: opts.K3sVersion,
Arch: opts.Arch,
MetaVersion: "v1",
Name: opts.Name,
Version: opts.BuildVersion,
K3sVersion: opts.K3sVersion,
Arch: opts.Arch,
ImageBundleFormat: imageFormat,
}

if opts.ConfigFile != "" {
Expand Down Expand Up @@ -186,33 +191,29 @@ func (b *builder) bundleImages(opts *types.BuildOptions, parser types.ManifestPa

log.Info("Detected the following images to bundle with the package:", imageNames)

downloader := images.NewImageDownloader()

var imgRdr io.ReadCloser
if opts.CreateRegistry {
log.Info("Building private image registry to bundle with the package")
artifacts, err := images.NewImageDownloader().BuildRegistry(&types.BuildRegistryOptions{
imgRdr, err = downloader.BuildRegistry(&types.BuildRegistryOptions{
Name: opts.Name,
AppVersion: opts.BuildVersion,
Arch: opts.Arch,
Images: imageNames,
PullPolicy: opts.PullPolicy,
// TODO: Make more configurable
})
if err != nil {
return err
}
for _, artifact := range artifacts {
if err := b.writer.Put(artifact); err != nil {
return err
}
}
return nil
} else {
log.Info("Exporting images to tar archives to bundle with the package")
// TODO: Switch to opts here as well
imgRdr, err = downloader.SaveImages(imageNames, opts.Arch, opts.PullPolicy)
}

rdr, err := images.NewImageDownloader().SaveImages(imageNames, opts.Arch, opts.PullPolicy)
if err != nil {
return err
}

log.Info("Adding container images to package")
images, err := util.ArtifactFromReader(types.ArtifactImages, types.ManifestUserImagesFile, rdr)
images, err := util.ArtifactFromReader(types.ArtifactImages, types.ManifestUserImagesFile, imgRdr)
if err != nil {
return err
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ var (
installDockerOpts types.DockerClusterOptions
)

// TODO: Add flags for user to supply registry certs, port, and/or password

func init() {

var currentUser *user.User
Expand Down
114 changes: 6 additions & 108 deletions pkg/images/build_registry.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
package images

import (
"bytes"
"context"
"errors"
"fmt"
"io/ioutil"
"io"
"time"

dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"golang.org/x/crypto/bcrypt"

"github.com/tinyzimmer/k3p/pkg/images/registry"
"github.com/tinyzimmer/k3p/pkg/log"
"github.com/tinyzimmer/k3p/pkg/types"
"github.com/tinyzimmer/k3p/pkg/util"
)

const kubenabImage = "docker.bintray.io/kubenab:0.3.4"

var requiredRegistryImages = []string{"registry:2", "busybox", kubenabImage}
var requiredRegistryImages = []string{"registry:2", "busybox", registry.KubenabImage}

func setOptDefaults(opts *types.BuildRegistryOptions) *types.BuildRegistryOptions {
if opts.RegistrySecret == "" {
opts.RegistrySecret = util.GenerateToken(16)
}

if opts.AppVersion == "" {
opts.AppVersion = types.VersionLatest
}

if opts.RegistryNodePort == "" {
opts.RegistryNodePort = "30100"
}

if opts.PullPolicy == "" {
opts.PullPolicy = types.PullPolicyAlways
}

return opts
}

func (d *dockerImageDownloader) BuildRegistry(opts *types.BuildRegistryOptions) ([]*types.Artifact, error) {
func (d *dockerImageDownloader) BuildRegistry(opts *types.BuildRegistryOptions) (io.ReadCloser, error) {
opts = setOptDefaults(opts)

cli, err := getDockerClient()
Expand All @@ -50,85 +38,6 @@ func (d *dockerImageDownloader) BuildRegistry(opts *types.BuildRegistryOptions)
}
defer cli.Close()

regDataImgName := fmt.Sprintf("%s-private-registry-data:%s", opts.Name, opts.AppVersion)

// Generate certificates for the registry
// TODO: Allow user to supply certificates
log.Info("Generating PKI for registry TLS")
caCert, caPriv, err := generateCACertificate(opts.Name)
if err != nil {
return nil, err
}
registryCert, registryPriv, err := generateRegistryCertificate(caCert, caPriv, opts.Name)
if err != nil {
return nil, err
}
caCertPem, _, err := encodeToPEM(caCert, caPriv)
if err != nil {
return nil, err
}
registryCertPEM, registryKeyPEM, err := encodeToPEM(registryCert, registryPriv)
if err != nil {
return nil, err
}

caCertificate := &types.Artifact{
Type: types.ArtifactEtc,
Name: "registry-ca.crt",
Body: ioutil.NopCloser(bytes.NewReader(caCertPem)),
Size: int64(len(caCertPem)),
}

// Generate htpasswd file for the registry
log.Info("Generating secrets for registry authentication")
passwordBytes, err := bcrypt.GenerateFromPassword([]byte(opts.RegistrySecret), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
htpasswd := append([]byte("registry:"), passwordBytes...)
htpasswd = append(htpasswd, []byte("\n")...)

// Create a manifest for the registry
log.Info("Generating kubernetes manifests for the private registry")
var buf bytes.Buffer
err = registryTmpl.Execute(&buf, map[string]string{
"TLSCertificate": string(registryCertPEM),
"TLSPrivateKey": string(registryKeyPEM),
"TLSCACertificate": string(caCertPem),
"RegistryAuthHtpasswd": string(htpasswd),
"KubenabImage": kubenabImage,
"RegistryDataImage": regDataImgName,
"RegistryNodePort": opts.RegistryNodePort,
})
if err != nil {
return nil, err
}
body := buf.Bytes()
deploymentManifest := &types.Artifact{
Type: types.ArtifactManifest,
Name: fmt.Sprintf("%s-private-registry-deployment.yaml", opts.Name),
Body: ioutil.NopCloser(bytes.NewReader(body)),
Size: int64(len(body)),
}

// Generate a registries.yaml
var yamlBuf bytes.Buffer
err = registriesYamlTmpl.Execute(&yamlBuf, map[string]string{
"Username": "registry",
"Password": opts.RegistrySecret,
"RegistryNodePort": opts.RegistryNodePort,
})
if err != nil {
return nil, err
}
registriesBody := yamlBuf.Bytes()
registriesYamlArtifact := &types.Artifact{
Type: types.ArtifactEtc,
Name: "registries.yaml",
Body: ioutil.NopCloser(bytes.NewReader(registriesBody)),
Size: int64(len(registriesBody)),
}

// Ensure all needed images are present
userImages := sanitizeImageNameSlice(opts.Images)
for _, img := range append(requiredRegistryImages, userImages...) {
Expand Down Expand Up @@ -228,22 +137,11 @@ func (d *dockerImageDownloader) BuildRegistry(opts *types.BuildRegistryOptions)
}

// Commit the registry volume container to an image
_, err = cli.ContainerCommit(context.TODO(), volContainerID, dockertypes.ContainerCommitOptions{Reference: regDataImgName})
_, err = cli.ContainerCommit(context.TODO(), volContainerID, dockertypes.ContainerCommitOptions{Reference: opts.RegistryImageName()})
if err != nil {
return nil, err
}

// Save all images for the registry
rdr, err := cli.ImageSave(context.TODO(), append(requiredRegistryImages, regDataImgName))
if err != nil {
return nil, err
}

// Create artifact for registry images
registryArtifact, err := util.ArtifactFromReader(types.ArtifactImages, "private-registry.tar", rdr)
if err != nil {
return nil, err
}

return []*types.Artifact{caCertificate, registriesYamlArtifact, deploymentManifest, registryArtifact}, nil
return cli.ImageSave(context.TODO(), append(requiredRegistryImages, opts.RegistryImageName()))
}
Loading

0 comments on commit cefdab2

Please sign in to comment.