Skip to content

Commit

Permalink
feat: replace bootkube with Talos-managed control plane
Browse files Browse the repository at this point in the history
Control plane components are running as static pods managed by the
kubelets.

Whole subsystem is managed via resources/controllers from os-runtime.

Many supporting changes/refactoring to enable new code paths.

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
  • Loading branch information
smira authored and talos-bot committed Jan 26, 2021
1 parent a2b6939 commit 0aaf8fa
Show file tree
Hide file tree
Showing 81 changed files with 5,948 additions and 1,645 deletions.
27 changes: 5 additions & 22 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ COPY ./api/cluster/cluster.proto /api/cluster/cluster.proto
RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api cluster/cluster.proto
COPY ./api/resource/resource.proto /api/resource/resource.proto
RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api resource/resource.proto
COPY ./api/inspect/inspect.proto /api/inspect/inspect.proto
RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api inspect/inspect.proto
# Gofumports generated files to adjust import order
RUN gofumports -w -local github.com/talos-systems/talos /api/

Expand All @@ -112,6 +114,7 @@ COPY --from=generate-build /api/network/*.pb.go /pkg/machinery/api/network/
COPY --from=generate-build /api/cluster/*.pb.go /pkg/machinery/api/cluster/
COPY --from=generate-build /api/storage/*.pb.go /pkg/machinery/api/storage/
COPY --from=generate-build /api/resource/*.pb.go /pkg/machinery/api/resource/
COPY --from=generate-build /api/inspect/*.pb.go /pkg/machinery/api/inspect/
COPY --from=generate-build /pkg/machinery/config/types/v1alpha1/*_doc.go /pkg/machinery/config/types/v1alpha1/

# The base target provides a container that can be used to build all Talos
Expand Down Expand Up @@ -268,27 +271,6 @@ RUN printf "FROM scratch\nCOPY ./routerd /routerd\nENTRYPOINT [\"/routerd\"]" >
RUN --security=insecure img build --tag ${USERNAME}/routerd:${TAG} --output type=docker,dest=/routerd.tar --no-console .


# The bootkube target builds the bootkube image.

FROM base AS bootkube-build
ARG SHA
ARG TAG
ARG PKGS
ARG EXTRAS
ARG VERSION_PKG="github.com/talos-systems/talos/pkg/version"
WORKDIR /src/internal/app/bootkube
RUN --mount=type=cache,target=/.cache/go-build go build -ldflags "-s -w -X ${VERSION_PKG}.Name=Server -X ${VERSION_PKG}.SHA=${SHA} -X ${VERSION_PKG}.Tag=${TAG} -X ${VERSION_PKG}.PkgsVersion=${PKGS} -X ${VERSION_PKG}.ExtrasVersion=${EXTRAS}" -o /bootkube
RUN chmod +x /bootkube

FROM base AS bootkube-image
ARG TAG
ARG USERNAME
COPY --from=bootkube-build /bootkube /scratch/bootkube
WORKDIR /scratch
RUN printf "FROM scratch\nCOPY ./bootkube /bootkube\nENTRYPOINT [\"/bootkube\"]" > Dockerfile
RUN --security=insecure img build --tag ${USERNAME}/bootkube:${TAG} --output type=docker,dest=/bootkube.tar --no-console .


# The talosctl targets build the talosctl binaries.

FROM base AS talosctl-linux-amd64-build
Expand Down Expand Up @@ -392,7 +374,6 @@ COPY --from=pkg-kmod /usr/lib/libkmod.* /rootfs/lib/
COPY --from=pkg-kernel /lib/modules /rootfs/lib/modules
COPY --from=machined /machined /rootfs/sbin/init
COPY --from=apid-image /apid.tar /rootfs/usr/images/
COPY --from=bootkube-image /bootkube.tar /rootfs/usr/images/
COPY --from=timed-image /timed.tar /rootfs/usr/images/
COPY --from=trustd-image /trustd.tar /rootfs/usr/images/
COPY --from=networkd-image /networkd.tar /rootfs/usr/images/
Expand Down Expand Up @@ -645,6 +626,7 @@ RUN protoc \
-I/protos \
-I/protos/common \
-I/protos/health \
-I/protos/inspect \
-I/protos/machine \
-I/protos/network \
-I/protos/resource \
Expand All @@ -656,6 +638,7 @@ RUN protoc \
--doc_out=/tmp \
/protos/common/*.proto \
/protos/health/*.proto \
/protos/inspect/*.proto \
/protos/machine/*.proto \
/protos/network/*.proto \
/protos/resource/*.proto \
Expand Down
42 changes: 42 additions & 0 deletions api/inspect/inspect.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
syntax = "proto3";

package inspect;

option go_package = "github.com/talos-systems/talos/pkg/machinery/api/inspect";
option java_multiple_files = true;
option java_outer_classname = "InspectApi";
option java_package = "com.inspect.api";

import "google/protobuf/empty.proto";
import "common/common.proto";

// The inspect service definition.
//
// InspectService provides auxilary API to inspect OS internals.
service InspectService {
rpc ControllerRuntimeDependencies(google.protobuf.Empty) returns (ControllerRuntimeDependenciesResponse);
}

// The ControllerRuntimeDependency message contains the graph of controller-resource dependencies.
message ControllerRuntimeDependency {
common.Metadata metadata = 1;
repeated ControllerDependencyEdge edges = 2;
}

message ControllerRuntimeDependenciesResponse { repeated ControllerRuntimeDependency messages = 1; }

enum DependencyEdgeType {
MANAGES = 0;
STRONG = 1;
WEAK = 2;
}

message ControllerDependencyEdge {
string controller_name = 1;

DependencyEdgeType edge_type = 2;

string resource_namespace = 3;
string resource_type = 4;
string resource_id = 5;
}
1 change: 1 addition & 0 deletions api/machine/machine.proto
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ message ServiceStateEvent {
};
Action action = 2;
string message = 3;
ServiceHealth health = 4;
};

message EventsRequest {
Expand Down
7 changes: 3 additions & 4 deletions cmd/talosctl/cmd/talos/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import (

"github.com/spf13/cobra"

"github.com/talos-systems/talos/internal/app/bootkube/images"
imagespkg "github.com/talos-systems/talos/pkg/images"
"github.com/talos-systems/talos/pkg/images"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
)

Expand Down Expand Up @@ -44,8 +43,8 @@ var imagesCmd = &cobra.Command{
fmt.Printf("%s\n", images.KubeScheduler)
fmt.Printf("%s\n", images.KubeProxy)
fmt.Printf("%s\n", images.Kubelet)
fmt.Printf("%s\n", images.PodCheckpointer)
fmt.Printf("%s\n", imagespkg.DefaultInstallerImage)
fmt.Printf("%s\n", images.Installer)
fmt.Printf("%s\n", images.Pause)

return nil
},
Expand Down
185 changes: 185 additions & 0 deletions cmd/talosctl/cmd/talos/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package talos

import (
"context"
"fmt"
"io"
"os"

"github.com/emicklei/dot"
"github.com/spf13/cobra"
"github.com/talos-systems/os-runtime/pkg/resource"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/talos-systems/talos/cmd/talosctl/pkg/talos/helpers"
"github.com/talos-systems/talos/pkg/cli"
"github.com/talos-systems/talos/pkg/machinery/api/inspect"
"github.com/talos-systems/talos/pkg/machinery/client"
)

// inspectCmd represents the inspect command.
var inspectCmd = &cobra.Command{
Use: "inspect",
Short: "Inspect internals of Talos",
Long: ``,
}

var inspectDependenciesCmdFlags struct {
withResources bool
}

// inspectDependenciesCmd represents the inspect dependencies command.
var inspectDependenciesCmd = &cobra.Command{
Use: "dependencies",
Short: "Inspect controller-resource dependencies as graphviz graph.",
Long: `Inspect controller-resource dependencies as graphviz graph.
Pipe the output of the command through the "dot" program (part of graphviz package)
to render the graph:
talosctl inspect dependencies | dot -Tpng > graph.png
`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return WithClient(func(ctx context.Context, c *client.Client) error {
if err := helpers.FailIfMultiNodes(ctx, "inspect dependencies"); err != nil {
return err
}

resp, err := c.Inspect.ControllerRuntimeDependencies(ctx)
if err != nil {
if resp == nil {
return fmt.Errorf("error getting controller runtime dependencies: %s", err)
}

cli.Warning("%s", err)
}

graph := dot.NewGraph(dot.Directed)

resourceTypeID := func(edge *inspect.ControllerDependencyEdge) string {
return fmt.Sprintf("%s:%s", edge.GetResourceNamespace(), edge.GetResourceType())
}

resourceID := func(r resource.Resource) string {
return r.Metadata().ID()
}

if inspectDependenciesCmdFlags.withResources {
resources := map[string][]resource.Resource{}

for _, msg := range resp.GetMessages() {
for _, edge := range msg.GetEdges() {
resourceType := resourceTypeID(edge)

if _, ok := resources[resourceType]; ok {
continue
}

listClient, err := c.Resources.List(ctx, edge.GetResourceNamespace(), edge.GetResourceType())
if err != nil {
return fmt.Errorf("error listing resources: %w", err)
}

for {
resp, err := listClient.Recv()
if err != nil {
if err == io.EOF || status.Code(err) == codes.Canceled {
break
}

return fmt.Errorf("error listing resources: %w", err)
}

if resp.Resource != nil {
resources[resourceType] = append(resources[resourceType], resp.Resource)
}
}
}
}

for _, msg := range resp.GetMessages() {
for _, edge := range msg.GetEdges() {
graph.Node(edge.ControllerName).Box()
}
}

for resourceType, resourceList := range resources {
cluster := graph.Subgraph(resourceType, dot.ClusterOption{})

for _, resource := range resourceList {
cluster.Node(resourceID(resource)).
Attr("shape", "note").
Attr("fillcolor", "azure2").
Attr("style", "filled")
}
}

for _, msg := range resp.GetMessages() {
for _, edge := range msg.GetEdges() {
for _, resource := range resources[resourceTypeID(edge)] {
if edge.GetResourceId() != "" && resource.Metadata().ID() != edge.GetResourceId() {
continue
}

switch edge.GetEdgeType() {
case inspect.DependencyEdgeType_MANAGES:
graph.Edge(graph.Node(edge.ControllerName), graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource))).Solid()
case inspect.DependencyEdgeType_STRONG:
graph.Edge(graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource)), graph.Node(edge.ControllerName)).Solid()
case inspect.DependencyEdgeType_WEAK:
graph.Edge(graph.Subgraph(resourceTypeID(edge)).Node(resourceID(resource)), graph.Node(edge.ControllerName)).Dotted()
}
}
}
}
} else {
for _, msg := range resp.GetMessages() {
for _, edge := range msg.GetEdges() {
graph.Node(edge.ControllerName).Box()

graph.Node(resourceTypeID(edge)).
Attr("shape", "note").
Attr("fillcolor", "azure2").
Attr("style", "filled")
}
}

for _, msg := range resp.GetMessages() {
for _, edge := range msg.GetEdges() {
idLabels := []string{}

if edge.GetResourceId() != "" {
idLabels = append(idLabels, edge.GetResourceId())
}

switch edge.GetEdgeType() {
case inspect.DependencyEdgeType_MANAGES:
graph.Edge(graph.Node(edge.ControllerName), graph.Node(resourceTypeID(edge))).Bold()
case inspect.DependencyEdgeType_STRONG:
graph.Edge(graph.Node(resourceTypeID(edge)), graph.Node(edge.ControllerName), idLabels...).Solid()
case inspect.DependencyEdgeType_WEAK:
graph.Edge(graph.Node(resourceTypeID(edge)), graph.Node(edge.ControllerName), idLabels...).Dotted()
}
}
}
}

graph.Write(os.Stdout)

return nil
})
},
}

func init() {
addCommand(inspectCmd)

inspectCmd.AddCommand(inspectDependenciesCmd)
inspectDependenciesCmd.Flags().BoolVar(&inspectDependenciesCmdFlags.withResources, "with-resources", false, "display live resource information with dependencies")
}
Loading

0 comments on commit 0aaf8fa

Please sign in to comment.