add image volume

This commit is contained in:
iwilltry42 2019-12-04 08:19:42 +01:00
parent 60659c74c8
commit e6d7726ffb
9 changed files with 216 additions and 13 deletions

View File

@ -64,6 +64,9 @@ func NewCmdCreateCluster() *cobra.Command {
cmd.Flags().StringArrayP("volume", "v", nil, "Mount volumes into the nodes (Format: `--volume [SOURCE:]DEST[@NODEFILTER[;NODEFILTER...]]`")
cmd.Flags().StringArrayP("port", "p", nil, "Map ports from the node containers to the host (Format: `[HOST:][HOSTPORT:]CONTAINERPORT[/PROTOCOL][@NODEFILTER]`)")
/* Image Importing */
cmd.Flags().Bool("no-image-volume", false, "Disable the creation of a volume for importing images")
/* Multi Master Configuration */ // TODO: to implement (whole multi master thingy)
// multi-master - general
cmd.Flags().Bool("no-lb", false, "Disable automatic deployment of a load balancer in Multi-Master setups")
@ -277,11 +280,22 @@ func parseCreateClusterCmd(cmd *cobra.Command, args []string) (runtimes.Runtime,
}
}
/* generate cluster */
// --no-image-volume
noImageVolume, err := cmd.Flags().GetBool("no-image-volume")
if err != nil {
log.Fatalln(err)
}
/*******************
* generate cluster *
********************/
cluster := &k3d.Cluster{
Name: args[0], // TODO: validate name0
Network: network,
Secret: secret,
ClusterCreationOpts: &k3d.ClusterCreationOpts{
DisableImageVolume: noImageVolume,
},
}
// generate list of nodes

View File

@ -38,9 +38,10 @@ func NewCmdLoadImage() *cobra.Command {
Use: "image",
Short: "Load an image from docker into a k3d cluster.",
Long: `Load an image from docker into a k3d cluster.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
runtime, images, clusters := parseLoadImageCmd(cmd, args)
log.Debugln("Load Images not yet implemented: ", runtime, images, clusters)
log.Debugf("Load images [%+v] from runtime [%s] into clusters [%+v]", runtime, images, clusters)
},
}

View File

@ -70,6 +70,25 @@ func CreateCluster(cluster *k3d.Cluster, runtime k3drt.Runtime) error {
cluster.Secret = GenerateClusterSecret()
}
/*
* Cluster-Wide volumes
* - image volume (for importing images)
*/
if !cluster.ClusterCreationOpts.DisableImageVolume {
imageVolumeName := fmt.Sprintf("%s-images", cluster.Name)
if err := runtime.CreateVolume(imageVolumeName, map[string]string{"k3d.cluster": cluster.Name}); err != nil {
log.Errorln("Failed to create image volume '%s' for cluster '%s'", imageVolumeName, cluster.Name)
return err
}
extraLabels["k3d.cluster.volumes.imagevolume"] = imageVolumeName
// attach volume to nodes
for _, node := range cluster.Nodes {
node.Volumes = append(node.Volumes, fmt.Sprintf("%s:%s", imageVolumeName, k3d.DefaultImageVolumeMountPath))
}
}
/*
* Nodes
*/
@ -209,6 +228,15 @@ func DeleteCluster(cluster *k3d.Cluster, runtime k3drt.Runtime) error {
}
}
// delete image volume
if imagevolume, ok := cluster.Nodes[0].Labels["k3d.cluster.volumes.imagevolume"]; ok {
log.Infof("Deleting image volume '%s'", imagevolume)
if err := runtime.DeleteVolume(imagevolume); err != nil {
log.Warningf("Failed to delete image volume '%s' of cluster '%s': Try to delete it manually", cluster.Name, imagevolume)
}
}
// return error if we failed to delete a node
if failed > 0 {
return fmt.Errorf("Failed to delete %d nodes: Try to delete them manually", failed)
}

View File

@ -22,12 +22,20 @@ THE SOFTWARE.
package cluster
import (
"github.com/rancher/k3d/pkg/runtimes"
k3d "github.com/rancher/k3d/pkg/types"
log "github.com/sirupsen/logrus"
)
// StartToolsContainer will start a new k3d tools container and connect it to the network of the chosen cluster
func StartToolsContainer(cluster *k3d.Cluster) error {
log.Debugln("starttoolscontainer")
return nil
// LoadImagesIntoCluster starts up a k3d tools container for the selected clusters and uses it to export
// images from the runtime to import them into the nodes of the selected cluster
func LoadImagesIntoCluster(runtime runtimes.Runtime, images []string, clusters *k3d.Cluster) {
}
// startToolsContainer will start a new k3d tools container and connect it to the network of the chosen cluster
func startToolsContainer(runtime runtimes.Runtime, cluster *k3d.Cluster) (string, error) {
log.Debugln("starttoolscontainer")
return "", nil
}

View File

@ -0,0 +1,32 @@
/*
Copyright © 2019 Thorsten Klein <iwilltry42@gmail.com>
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.
*/
package containerd
// CreateVolume creates a new named volume
func (d Containerd) CreateVolume(name string, labels map[string]string) error {
return nil
}
// DeleteVolume creates a new named volume
func (d Containerd) DeleteVolume(name string) error {
return nil
}

View File

@ -0,0 +1,96 @@
/*
Copyright © 2019 Thorsten Klein <iwilltry42@gmail.com>
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.
*/
package docker
import (
"context"
"fmt"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
k3d "github.com/rancher/k3d/pkg/types"
log "github.com/sirupsen/logrus"
)
// CreateVolume creates a new named volume
func (d Docker) CreateVolume(name string, labels map[string]string) error {
// (0) create new docker client
ctx := context.Background()
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Errorln("Failed to create docker client")
return err
}
// (1) create volume
volumeCreateOptions := volume.VolumeCreateBody{
Name: name,
Labels: k3d.DefaultObjectLabels,
Driver: "local", // TODO: allow setting driver + opts
DriverOpts: map[string]string{},
}
for k, v := range labels {
volumeCreateOptions.Labels[k] = v
}
vol, err := docker.VolumeCreate(ctx, volumeCreateOptions)
if err != nil {
log.Errorf("Failed to create volume '%s'", name)
return err
}
log.Infof("Created volume '%s'", vol.Name)
return nil
}
// DeleteVolume creates a new named volume
func (d Docker) DeleteVolume(name string) error {
// (0) create new docker client
ctx := context.Background()
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
log.Errorln("Failed to create docker client")
return err
}
// get volume and delete it
vol, err := docker.VolumeInspect(ctx, name)
if err != nil {
log.Errorf("Failed to find volume '%s'", name)
return err
}
// check if volume is still in use
if vol.UsageData != nil {
if vol.UsageData.RefCount > 0 {
log.Errorf("Failed to delete volume '%s'")
return fmt.Errorf("Volume '%s' is still referenced by %d containers", name, vol.UsageData.RefCount)
}
}
// remove volume
if err := docker.VolumeRemove(ctx, name, true); err != nil {
log.Errorf("Failed to delete volume '%s'", name)
return err
}
return nil
}

View File

@ -47,6 +47,8 @@ type Runtime interface {
DeleteNetwork(ID string) error
StartNode(*k3d.Node) error
StopNode(*k3d.Node) error
CreateVolume(string, map[string]string) error
DeleteVolume(string) error
// ExecContainer() error
// DeleteContainer() error
GetNodeLogs(*k3d.Node) (io.ReadCloser, error)

View File

@ -72,15 +72,24 @@ var DefaultNodeEnv = []string{
"K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml",
}
// DefaultImageVolumeMountPath defines the mount path inside k3d nodes where we will mount the shared image volume by default
const DefaultImageVolumeMountPath = "/k3d/images"
// ClusterCreationOpts describe a set of options one can set when creating a cluster
type ClusterCreationOpts struct {
DisableImageVolume bool
}
// Cluster describes a k3d cluster
type Cluster struct {
Name string `yaml:"name" json:"name,omitempty"`
Network string `yaml:"network" json:"network,omitempty"`
Secret string `yaml:"cluster_secret" json:"clusterSecret,omitempty"`
Nodes []*Node `yaml:"nodes" json:"nodes,omitempty"`
InitNode *Node // init master node
MasterLoadBalancer *ClusterLoadbalancer `yaml:"master_loadbalancer" json:"masterLoadBalancer,omitempty"`
ExternalDatastore ExternalDatastore `yaml:"external_datastore" json:"externalDatastore,omitempty"`
Name string `yaml:"name" json:"name,omitempty"`
Network string `yaml:"network" json:"network,omitempty"`
Secret string `yaml:"cluster_secret" json:"clusterSecret,omitempty"`
Nodes []*Node `yaml:"nodes" json:"nodes,omitempty"`
InitNode *Node // init master node
MasterLoadBalancer *ClusterLoadbalancer `yaml:"master_loadbalancer" json:"masterLoadBalancer,omitempty"`
ExternalDatastore ExternalDatastore `yaml:"external_datastore" json:"externalDatastore,omitempty"`
ClusterCreationOpts *ClusterCreationOpts `yaml:"options" json:"options,omitempty"`
}
// Node describes a k3d node

View File

@ -163,6 +163,7 @@ Here's how k3d types should translate to a runtime type:
- cluster NAME
- --all
- node NAME
- --all
- get
- cluster NAME
- --no-headers
@ -178,3 +179,15 @@ Here's how k3d types should translate to a runtime type:
- cluster NAME
- --all
- node NAME
## tools
- maybe rename `k3d load` to `k3d tools` and add tool cmds there?
- e.g. `k3d tools import-images`
- let's you set tools container version
- `k3d tools --image k3d-tools:v2 import-images`
## extra commands
- `k3d prune` to prune all dangling resources
- nodes, volumes, networks