createNode: copy as many details as possible from existing
- we now use the full containerJSON details when getting a node - we now use as many details as possible to copy k3d settings from an existing node when adding a new node to a running cluster
This commit is contained in:
parent
da8adf5469
commit
c061104b53
@ -2,4 +2,5 @@ title: Usage
|
|||||||
arrange:
|
arrange:
|
||||||
- commands.md
|
- commands.md
|
||||||
- kubeconfig.md
|
- kubeconfig.md
|
||||||
|
- multimaster.md
|
||||||
- guides
|
- guides
|
2
go.mod
2
go.mod
@ -21,7 +21,7 @@ require (
|
|||||||
github.com/gogo/protobuf v1.3.1 // indirect
|
github.com/gogo/protobuf v1.3.1 // indirect
|
||||||
github.com/golang/protobuf v1.4.0 // indirect
|
github.com/golang/protobuf v1.4.0 // indirect
|
||||||
github.com/heroku/docker-registry-client v0.0.0-20190909225348-afc9e1acc3d5
|
github.com/heroku/docker-registry-client v0.0.0-20190909225348-afc9e1acc3d5
|
||||||
github.com/imdario/mergo v0.3.9 // indirect
|
github.com/imdario/mergo v0.3.9
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
||||||
|
@ -25,10 +25,10 @@ package cluster
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/imdario/mergo"
|
||||||
"github.com/rancher/k3d/pkg/runtimes"
|
"github.com/rancher/k3d/pkg/runtimes"
|
||||||
k3d "github.com/rancher/k3d/pkg/types"
|
k3d "github.com/rancher/k3d/pkg/types"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@ -70,27 +70,21 @@ func AddNodeToCluster(runtime runtimes.Runtime, node *k3d.Node, cluster *k3d.Clu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get node details
|
||||||
|
chosenNode, err = GetNode(chosenNode, runtime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
log.Debugf("Copying configuration from existing node %+v", chosenNode)
|
log.Debugf("Copying configuration from existing node %+v", chosenNode)
|
||||||
|
|
||||||
// get config from labels
|
// merge node config of new node into existing node config
|
||||||
for k, v := range chosenNode.Labels {
|
if err := mergo.MergeWithOverwrite(chosenNode, *node); err != nil {
|
||||||
if strings.HasPrefix(k, "k3d") {
|
log.Errorln("Failed to merge new node config into existing node config")
|
||||||
node.Labels[k] = v
|
return err
|
||||||
}
|
|
||||||
if k == "k3d.cluster.url" {
|
|
||||||
node.Env = append(node.Env, fmt.Sprintf("K3S_URL=%s", v))
|
|
||||||
}
|
|
||||||
if k == "k3d.cluster.secret" {
|
|
||||||
node.Env = append(node.Env, fmt.Sprintf("K3S_TOKEN=%s", v))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup: get config from environment variables
|
node = chosenNode
|
||||||
for _, env := range chosenNode.Env {
|
|
||||||
if strings.HasPrefix(env, "K3S_") {
|
|
||||||
node.Env = append(node.Env, env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Resulting node %+v", node)
|
log.Debugf("Resulting node %+v", node)
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
|
|
||||||
// CreateNode creates a new container
|
// CreateNode creates a new container
|
||||||
func (d Docker) CreateNode(node *k3d.Node) error {
|
func (d Docker) CreateNode(node *k3d.Node) error {
|
||||||
log.Debugln("docker.CreateNode...")
|
|
||||||
|
|
||||||
// translate node spec to docker container specs
|
// translate node spec to docker container specs
|
||||||
dockerNode, err := TranslateNodeToContainer(node)
|
dockerNode, err := TranslateNodeToContainer(node)
|
||||||
@ -172,9 +171,30 @@ func getContainersByLabel(labels map[string]string) ([]types.Container, error) {
|
|||||||
log.Errorln("Failed to list containers")
|
log.Errorln("Failed to list containers")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return containers, nil
|
return containers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getContainer details returns the containerjson with more details
|
||||||
|
func getContainerDetails(containerID string) (types.ContainerJSON, error) {
|
||||||
|
// (0) create docker client
|
||||||
|
ctx := context.Background()
|
||||||
|
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
|
if err != nil {
|
||||||
|
return types.ContainerJSON{}, fmt.Errorf("Failed to create docker client. %+v", err)
|
||||||
|
}
|
||||||
|
defer docker.Close()
|
||||||
|
|
||||||
|
containerDetails, err := docker.ContainerInspect(ctx, containerID)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Failed to get details for container '%s'", containerID)
|
||||||
|
return types.ContainerJSON{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerDetails, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// GetNode tries to get a node container by its name
|
// GetNode tries to get a node container by its name
|
||||||
func (d Docker) GetNode(node *k3d.Node) (*k3d.Node, error) {
|
func (d Docker) GetNode(node *k3d.Node) (*k3d.Node, error) {
|
||||||
container, err := getNodeContainer(node)
|
container, err := getNodeContainer(node)
|
||||||
@ -183,9 +203,14 @@ func (d Docker) GetNode(node *k3d.Node) (*k3d.Node, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err = TranslateContainerToNode(container)
|
containerDetails, err := getContainerDetails(container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to translate container for node '%s' to node object", node.Name)
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err = TranslateContainerDetailsToNode(containerDetails)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to translate container details for node '%s' to node object", node.Name)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ THE SOFTWARE.
|
|||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
@ -117,3 +118,79 @@ func TranslateContainerToNode(cont *types.Container) (*k3d.Node, error) {
|
|||||||
}
|
}
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TranslateContainerDetailsToNode translates a docker containerJSON object into a k3d node representation
|
||||||
|
func TranslateContainerDetailsToNode(containerDetails types.ContainerJSON) (*k3d.Node, error) {
|
||||||
|
|
||||||
|
// translate portMap to string representation
|
||||||
|
ports := []string{}
|
||||||
|
for containerPort, portBindingList := range containerDetails.HostConfig.PortBindings {
|
||||||
|
for _, hostInfo := range portBindingList {
|
||||||
|
ports = append(ports, fmt.Sprintf("%s:%s:%s", hostInfo.HostIP, hostInfo.HostPort, containerPort))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restart -> we only set 'unless-stopped' upon cluster creation
|
||||||
|
restart := false
|
||||||
|
if containerDetails.HostConfig.RestartPolicy.IsAlways() || containerDetails.HostConfig.RestartPolicy.IsUnlessStopped() {
|
||||||
|
restart = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the clusterNetwork
|
||||||
|
clusterNetwork := ""
|
||||||
|
for networkName := range containerDetails.NetworkSettings.Networks {
|
||||||
|
if strings.HasPrefix(networkName, fmt.Sprintf("%s-%s", k3d.DefaultObjectNamePrefix, containerDetails.Config.Labels["k3d.cluster"])) { // FIXME: catch error if label 'k3d.cluster' does not exist, but this should also never be the case
|
||||||
|
clusterNetwork = networkName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// masterOpts
|
||||||
|
masterOpts := k3d.MasterOpts{IsInit: false}
|
||||||
|
for k, v := range containerDetails.Config.Labels {
|
||||||
|
/*
|
||||||
|
node.Labels["k3d.master.api.hostIP"] = node.MasterOpts.ExposeAPI.HostIP // TODO: maybe get docker machine IP here
|
||||||
|
node.Labels["k3d.master.api.host"] = node.MasterOpts.ExposeAPI.Host
|
||||||
|
node.Labels["k3d.master.api.port"] = node.MasterOpts.ExposeAPI.Port
|
||||||
|
*/
|
||||||
|
if k == "k3d.master.api.hostIP" {
|
||||||
|
masterOpts.ExposeAPI.HostIP = v
|
||||||
|
} else if k == "k3d.master.api.host" {
|
||||||
|
masterOpts.ExposeAPI.Host = v
|
||||||
|
} else if k == "k3d.master.api.port" {
|
||||||
|
masterOpts.ExposeAPI.Port = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// env vars: only copy K3S_* and K3D_* // FIXME: should we really do this? Might be unexpected, if user has e.g. HTTP_PROXY vars
|
||||||
|
env := []string{}
|
||||||
|
for _, envVar := range containerDetails.Config.Env {
|
||||||
|
if strings.HasPrefix(envVar, "K3D_") || strings.HasPrefix(envVar, "K3S_") {
|
||||||
|
env = append(env, envVar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// labels: only copy k3d.* labels
|
||||||
|
labels := map[string]string{}
|
||||||
|
for k, v := range containerDetails.Config.Labels {
|
||||||
|
if strings.HasPrefix(k, "k3d") {
|
||||||
|
labels[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node := &k3d.Node{
|
||||||
|
Name: strings.TrimPrefix(containerDetails.Name, "/"), // container name with leading '/' cut off
|
||||||
|
Role: k3d.NodeRoles[containerDetails.Config.Labels["k3d.role"]],
|
||||||
|
Image: containerDetails.Image,
|
||||||
|
Volumes: containerDetails.HostConfig.Binds,
|
||||||
|
Env: env,
|
||||||
|
Cmd: containerDetails.Config.Cmd,
|
||||||
|
Args: []string{}, // empty, since Cmd already contains flags
|
||||||
|
Ports: ports,
|
||||||
|
Restart: restart,
|
||||||
|
Labels: labels,
|
||||||
|
Network: clusterNetwork,
|
||||||
|
MasterOpts: masterOpts,
|
||||||
|
WorkerOpts: k3d.WorkerOpts{},
|
||||||
|
}
|
||||||
|
return node, nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user