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

Add repository option to image cache #244

Closed
wants to merge 13 commits into from
Closed
3 changes: 3 additions & 0 deletions pkg/clients/container/docker_tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ func (d *DockerTasks) CreateContainer(c *dtypes.Container) (string, error) {

// is this a priviledged container
hc.Privileged = c.Privileged
if c.Privileged {
hc.CgroupnsMode = "host"
}

// are we attaching the container to a sidecar network?
for _, n := range c.Networks {
Expand Down
65 changes: 51 additions & 14 deletions pkg/config/resources/cache/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package cache

import (
"fmt"
ctypes "github.com/jumppad-labs/jumppad/pkg/config/resources/container"
"math/rand"
"path/filepath"
"strings"

dtypes "github.com/docker/docker/api/types"
htypes "github.com/jumppad-labs/hclconfig/types"
Expand All @@ -17,9 +19,11 @@ import (
)

const cacheImage = "shipyardrun/docker-registry-proxy:0.6.3"
const defaultRegistries = "k8s.gcr.io gcr.io asia.gcr.io eu.gcr.io us.gcr.io quay.io ghcr.io docker.pkg.github.com"

type Provider struct {
config *ImageCache
registries []Registry
client container.ContainerTasks
httpClient http.HTTP
log logger.Logger
Expand Down Expand Up @@ -56,8 +60,26 @@ func (p *Provider) Create() error {
// get a list of dependent networks for the resource
dependentNetworks := p.findDependentNetworks()

var registries []string
var authRegistries []string

for _, reg := range p.config.Registries {
registries = append(registries, reg.Hostname)

if reg.Auth == nil {
continue
}

hostname := reg.Hostname
if len(reg.Auth.Hostname) > 0 {
hostname = reg.Auth.Hostname
registries = append(registries, reg.Auth.Hostname)
}
authRegistries = append(authRegistries, hostname+":::"+reg.Auth.Username+":::"+reg.Auth.Password)
}

if len(ids) == 0 {
_, err := p.createImageCache(dependentNetworks)
_, err := p.createImageCache(dependentNetworks, registries, authRegistries)
if err != nil {
return err
}
Expand All @@ -76,7 +98,10 @@ func (p *Provider) Destroy() error {

if len(ids) > 0 {
for _, id := range ids {
p.client.RemoveContainer(id, true)
err = p.client.RemoveContainer(id, true)
if err != nil {
p.log.Error(err.Error())
}
}
}

Expand Down Expand Up @@ -105,7 +130,7 @@ func (p *Provider) Changed() (bool, error) {
return false, nil
}

func (p *Provider) createImageCache(networks []string) (string, error) {
func (p *Provider) createImageCache(networks []string, registries []string, authRegistries []string) (string, error) {
fqdn := utils.FQDN(p.config.Name, p.config.Module, p.config.Type)

// Create the volume to store the cache
Expand Down Expand Up @@ -144,12 +169,14 @@ func (p *Provider) createImageCache(networks []string) (string, error) {
}

cc.Environment = map[string]string{
"CA_KEY_FILE": "/cache/ca/root.key",
"CA_CRT_FILE": "/cache/ca/root.cert",
"DOCKER_MIRROR_CACHE": "/cache/docker",
"ENABLE_MANIFEST_CACHE": "true",
"REGISTRIES": "k8s.gcr.io gcr.io asia.gcr.io eu.gcr.io us.gcr.io quay.io ghcr.io docker.pkg.github.com",
"ALLOW_PUSH": "true",
"CA_KEY_FILE": "/cache/ca/root.key",
"CA_CRT_FILE": "/cache/ca/root.cert",
"DOCKER_MIRROR_CACHE": "/cache/docker",
"ENABLE_MANIFEST_CACHE": "true",
"REGISTRIES": defaultRegistries + " " + strings.Join(registries[:], " "),
"AUTH_REGISTRY_DELIMITER": ":::",
"AUTH_REGISTRIES": strings.Join(authRegistries[:], " "),
"ALLOW_PUSH": "true",
}

// expose the docker proxy port on a random port num
Expand All @@ -161,10 +188,16 @@ func (p *Provider) createImageCache(networks []string) (string, error) {
},
}

// add the networks
cc.Networks = []types.NetworkAttachment{}
for _, n := range networks {
cc.Networks = append(cc.Networks, types.NetworkAttachment{ID: n})
cc.Networks = p.config.Networks.ToClientNetworkAttachments()

// add the name of the network, we only have the id
for i, n := range p.config.Networks {
net, err := p.client.FindNetwork(n.ID)
if err != nil {
return "", err
}

p.config.Networks[i].Name = net.Name
}

return p.client.CreateContainer(cc)
Expand All @@ -174,6 +207,10 @@ func (p *Provider) findDependentNetworks() []string {
nets := []string{}

for _, n := range p.config.DependsOn {
if strings.HasSuffix(n, ".id") {
// Ignore explicitly configured network dependencies
continue
}
target, err := p.client.FindNetwork(n)
if err != nil {
// ignore this network
Expand Down Expand Up @@ -225,7 +262,7 @@ func (p *Provider) reConfigureNetworks(dependentNetworks []string) error {
return fmt.Errorf("unable to attach cache to network: %s", err)
}

p.config.Networks = append(p.config.Networks, n)
p.config.Networks = append(p.config.Networks, ctypes.NetworkAttachment{ID: n})
}

added = append(added, n)
Expand Down
14 changes: 0 additions & 14 deletions pkg/config/resources/cache/resource.go

This file was deleted.

20 changes: 20 additions & 0 deletions pkg/config/resources/cache/resource_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cache

import (
"github.com/jumppad-labs/hclconfig/types"
ctypes "github.com/jumppad-labs/jumppad/pkg/config/resources/container"
)

// TypeImageCache is the resource string for a ImageCache resource
const TypeImageCache string = "image_cache"

// ImageCache defines a structure for creating ImageCache containers
type ImageCache struct {
// embedded type holding name, etc
types.ResourceMetadata `hcl:",remain"`

Registries []Registry `hcl:"registry,block" json:"registries,omitempty"`
//Networks []string `json:"networks" state:"true"` // Attach to the correct network // only when Image is specified

Networks ctypes.NetworkAttachments `hcl:"network,block" json:"networks,omitempty"` // Attach to the correct network // only when Image is specified
}
22 changes: 22 additions & 0 deletions pkg/config/resources/cache/resource_registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cache

import "github.com/jumppad-labs/hclconfig/types"

// RegistryAuth defines a structure for authenticating against a docker registry
type RegistryAuth struct {
// embedded type holding name, etc
types.ResourceMetadata `hcl:",remain"`

Hostname string `hcl:"hostname,optional" json:"hostname"` // Optional hostname for authentication
Username string `hcl:"username" json:"username"` // Username for authentication, should not be an email
Password string `hcl:"password" json:"password"` // Password for authentication
}

// Registry defines a structure for registering additional registries
type Registry struct {
// embedded type holding name, etc
types.ResourceMetadata `hcl:",remain"`

Hostname string `hcl:"hostname" json:"hostname"` // Hostname of the registry
Auth *RegistryAuth `hcl:"auth,block" json:"auth,omitempty"` // auth to authenticate against registry
}
32 changes: 24 additions & 8 deletions pkg/config/resources/nomad/provider_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ func (p *ClusterProvider) createServerNode(img ctypes.Image, volumeID string, is
// write the nomad config to a file
os.MkdirAll(p.config.ConfigDir, os.ModePerm)
serverConfigPath := path.Join(p.config.ConfigDir, "server_config.hcl")
ioutil.WriteFile(serverConfigPath, []byte(sc), os.ModePerm)
os.WriteFile(serverConfigPath, []byte(sc), os.ModePerm)

// create the server
// since the server is just a container create the container config and provider
Expand Down Expand Up @@ -498,8 +498,6 @@ func (p *ClusterProvider) createServerNode(img ctypes.Image, volumeID string, is
cc.Volumes = append(cc.Volumes, v.ToClientVolume())
}

cc.Environment = p.config.Environment

// expose the API server port
cc.Ports = []ctypes.Port{
{
Expand All @@ -522,7 +520,11 @@ func (p *ClusterProvider) createServerNode(img ctypes.Image, volumeID string, is
cc.Ports = append(cc.Ports, p.config.Ports.ToClientPorts()...)
cc.PortRanges = append(cc.PortRanges, p.config.PortRanges.ToClientPortRanges()...)

cc.Environment = map[string]string{}
cc.Environment = p.config.Environment
if cc.Environment == nil {
cc.Environment = map[string]string{}
}

err := p.appendProxyEnv(cc)
if err != nil {
return "", err
Expand All @@ -544,7 +546,7 @@ func (p *ClusterProvider) createClientNode(id string, image, volumeID, serverID

// write the default config to a file
clientConfigPath := path.Join(p.config.ConfigDir, "client_config.hcl")
ioutil.WriteFile(clientConfigPath, []byte(sc), os.ModePerm)
os.WriteFile(clientConfigPath, []byte(sc), os.ModePerm)

// create the server
// since the server is just a container create the container config and provider
Expand Down Expand Up @@ -624,7 +626,7 @@ func (p *ClusterProvider) createClientNode(id string, image, volumeID, serverID

func (p *ClusterProvider) appendProxyEnv(cc *ctypes.Container) error {
// load the CA from a file
ca, err := ioutil.ReadFile(filepath.Join(utils.CertsDir(""), "/root.cert"))
ca, err := os.ReadFile(filepath.Join(utils.CertsDir(""), "/root.cert"))
if err != nil {
return fmt.Errorf("unable to read root CA for proxy: %s", err)
}
Expand All @@ -640,10 +642,24 @@ func (p *ClusterProvider) appendProxyEnv(cc *ctypes.Container) error {
networkSubmasks = append(networkSubmasks, net.Subnet)
}

cc.Environment = p.config.Environment
if cc.Environment == nil {
cc.Environment = map[string]string{}
}

proxyBypass := utils.ProxyBypass + "," + strings.Join(networkSubmasks, ",")

cc.Environment["HTTP_PROXY"] = utils.HTTPProxyAddress()
cc.Environment["HTTPS_PROXY"] = utils.HTTPSProxyAddress()
if noProxy, ok := cc.Environment["NO_PROXY"]; ok {
proxyBypass += "," + noProxy
}

mirror := utils.HTTPProxyAddress()
if p.config.Cache != nil {
mirror = fmt.Sprintf("http://%s.image-cache.jumppad.dev:3128", p.config.Cache.ResourceMetadata.Name)
}

cc.Environment["HTTP_PROXY"] = mirror
cc.Environment["HTTPS_PROXY"] = mirror
cc.Environment["NO_PROXY"] = proxyBypass
cc.Environment["PROXY_CA"] = string(ca)

Expand Down
7 changes: 7 additions & 0 deletions pkg/config/resources/nomad/resource_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/jumppad-labs/hclconfig/types"
"github.com/jumppad-labs/jumppad/pkg/config"
itypes "github.com/jumppad-labs/jumppad/pkg/config/resources/cache"
ctypes "github.com/jumppad-labs/jumppad/pkg/config/resources/container"
"github.com/jumppad-labs/jumppad/pkg/utils"
)
Expand Down Expand Up @@ -56,6 +57,8 @@ type NomadCluster struct {
// ExternalIP is the ip address of the cluster, this generally resolves
// to the docker ip
ExternalIP string `hcl:"external_ip,optional" json:"external_ip,omitempty"`

Cache *itypes.ImageCache `hcl:"image_cache,optional" json:"image_cache,omitempty"`
}

const nomadBaseImage = "shipyardrun/nomad"
Expand Down Expand Up @@ -85,6 +88,10 @@ func (n *NomadCluster) Process() error {
// Process volumes
// make sure mount paths are absolute
for i, v := range n.Volumes {
if v.Type != "bind" && v.Type != "" {
// only change path for bind mounts
continue
}
n.Volumes[i].Source = utils.EnsureAbsolute(v.Source, n.File)
}

Expand Down
Loading