DEV Community

Cover image for Build own Kubernetes - Pods listing and deletion
Jonatan Ezron
Jonatan Ezron

Posted on • Edited on

Build own Kubernetes - Pods listing and deletion

In the previous article, we created and run the pods, in this article we will list and delete pods on command.

Before this article I had some refactor the code, The methods related to Pod and RunningPod structs are in pkg/pod/pod.go and access functions to run operations related to pods like creating a new pod is in pkg/pod/service.go


We want to List all the running pods, we implement a simple function in pkg/pod/service.go to list all the existing tasks:

func initContainerdConnection() (*containerd.Client, context.Context, error) {
    client, err := containerd.New(SOCKET_PATH)
    if err != nil {
        return nil, nil, err
    }

    ctx := namespaces.WithNamespace(context.Background(), NAMESPACE)

    return client, ctx, nil
}

func ListRunningPods() ([]string, error) {
    client, ctx, err := initContainerdConnection()
    if err != nil {
        return nil, err
    }

    runningPods := []string{}

    containers, err := client.Containers(ctx)
    if err != nil {
        return runningPods, err
    }

    for _, container := range containers {
        _, err = container.Task(ctx, cio.Load)

        if err == nil {
            runningPods = append(runningPods, container.ID())
        }
    }

    return runningPods, nil
}

Enter fullscreen mode Exit fullscreen mode

The initContainerdConnection function was created on the refactor phase, this function is called to create a client and ctx to make operations on containerd.
The function goes through every existing container and tries to Load to it, if no error returns this means there is a running task on the container, meaning the pod is running.

In the cmd/pod.go

var listCmd = &cobra.Command{
    Use:   "list",
    Short: "lists existing pods",
    RunE: func(cmd *cobra.Command, args []string) error {
        runningPods, err := pod.ListRunningPods()
        if err != nil {
            return err
        }

        for _, pod := range runningPods {
            fmt.Println(pod)
        }

        return nil
    },
}
Enter fullscreen mode Exit fullscreen mode

Let's check (for this I commented the kill and deletion of the pod creation):

sudo ./main pod create --registry docker.io/library/redis:alpine --name redis
pod created: redis-9079a2e3-87a0-4a08-8b96-14926b6edb45
starting pod
pod started: redis-9079a2e3-87a0-4a08-8b96-14926b6edb45
❯ sudo ./main pod list
redis-9079a2e3-87a0-4a08-8b96-14926b6edb45
Enter fullscreen mode Exit fullscreen mode

great, It works!

Now let's focus on the delete command, we want the delete to accept a pod id and delete it, it prints the deleted pod id.
So in cmd/pkd/pod.go:

var killCmd = &cobra.Command{
    Use:   "kill",
    Short: "kill existing pod",
    RunE: func(cmd *cobra.Command, args []string) error {
        id, err := pod.KillPod(name)
        if err != nil {
            return err
        }

        fmt.Println(id)

        return nil
    },
}

func init() {
.
.
.

    podCmd.AddCommand(killCmd)
    killCmd.Flags().StringVar(&name, "id", "", "the pod id (required)")
    killCmd.MarkFlagRequired("id")
}

Enter fullscreen mode Exit fullscreen mode

Now in the pkg/pod/service.go, we add a KillPod function, which searches for a container and container's task, creates from it a Pod and RunningPod struct, and executes the Kill and Delete methods. The creation of the structs is for the kill and delete to be handled properly.

func KillPod(name string) (string, error) {
    client, ctx, err := initContainerdConnection()
    if err != nil {
        return "", err
    }

    container, err := client.LoadContainer(ctx, name)
    if err != nil {
        return "", err
    }

    task, err := container.Task(ctx, cio.Load)
    if err != nil {
        return "", err
    }

    exitStatusC, err := task.Wait(ctx)
    if err != nil {
        return "", err
    }

    runningPod := RunningPod{
        task: &task,
        Pod: &Pod{
            client:    client,
            ctx:       &ctx,
            container: &container,
            Id:        name,
        },
        exitStatusC: exitStatusC,
    }

    _, err = runningPod.Kill()
    if err != nil {
        return "", err
    }

    runningPod.Pod.Delete()

    return name, nil
}

Enter fullscreen mode Exit fullscreen mode

Let's test our changes:

sudo ./main pod create --registry docker.io/library/redis:alpine --name redis
pod created: redis-3f6f15fb-ff52-4d61-937f-db01d02f1b61
starting pod
❯ sudo ./main pod list
redis-3f6f15fb-ff52-4d61-937f-db01d02f1b61
❯ sudo ./main pod kill --id redis-3f6f15fb-ff52-4d61-937f-db01d02f1b61
redis-3f6f15fb-ff52-4d61-937f-db01d02f1b61
❯ sudo ./main pod list
Enter fullscreen mode Exit fullscreen mode

Great, it works!


On the next article we will focus on Node setup and agent.

The full source code can be found here, the changes were in pkg/pod/service.go and cmd/pod.go.

Top comments (0)