add image volume
This commit is contained in:
parent
60659c74c8
commit
e6d7726ffb
@ -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
|
||||
|
@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
32
pkg/runtimes/containerd/volume.go
Normal file
32
pkg/runtimes/containerd/volume.go
Normal 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
|
||||
}
|
96
pkg/runtimes/docker/volume.go
Normal file
96
pkg/runtimes/docker/volume.go
Normal 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
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
||||
|
13
thoughts.md
13
thoughts.md
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user