자체 Kubernetes - 2부 - 포드 생성

처음에는 Kubernetes - Pod의 가장 작은 단위에 초점을 맞추고 이 장에서는 Pod를 만들고 실행하는 데 중점을 둘 것입니다. 각 컨테이너는 containerd에서 실행되며(개발 컴퓨터 또는 프로그램을 실행하는 위치에 containerd를 설치해야 함) 이를 통해 관리됩니다.

이 프로젝트를 시작할 때 Cobra을 사용하여 cmd 명령으로 기본 작업을 구현하고 나중에 계속해서 고급 작업을 수행할 것입니다.

cobra-cli를 사용하여 프로젝트를 초기화하고 pods 명령을 위한 새 명령 pod, 기존 pod 나열을 위한 목록, 새 pod 생성 및 실행을 위한 생성을 추가합니다(현재로서는).

cobra-cli init
cobra-cli add pod
cobra-cli add list
cobra-cli add create


pod list 또는 pod create를 실행할 수 있도록 명령을 cmd 파일 내의 단일 pod 파일 명령으로 이동합니다.

// cmd/pod.go
package cmd

import (
    "github.com/spf13/cobra"
)

var podCmd = &cobra.Command{
    Use:   "pod",
    Short: "The command line tool to run commands on pods",
}

var createCmd = &cobra.Command{
    Use:   "create",
    Short: "Create new pod",
    // Run: ,
}

var listCmd = &cobra.Command{
    Use:   "list",
    Short: "lists existing pods",
    // Run: ,
}

func init() {
    rootCmd.AddCommand(podCmd)
    podCmd.AddCommand(listCmd)
    podCmd.AddCommand(createCmd)
}

pkg/pod/pod.go에서 포드 생성을 구현해 보겠습니다. 지금은 포드 1개에서 컨테이너 1개만 지원합니다.
우리는 containerd를 사용하고 있으므로 시스템에서 실행 중인지 확인하십시오.
source on how to use the containerd package
우리는 containerd의 기존 Pod 인스턴스를 나타내는 Pod 구조체와 현재 실행 중인 Pod 인스턴스를 나타내는 RunningPod 구조체를 정의합니다.

type Pod struct {
    Id        string
    client    *containerd.Client
    ctx       *context.Context
    container *containerd.Container
}


Id - 포드에 대해 생성된 ID
client - 통신할 containerd 클라이언트
ctx - 사용할 컨텍스트, 클라이언트 메서드 호출
컨테이너 - 포드의 컨테이너 인스턴스

type RunningPod struct {
    Pod         *Pod
    task        *containerd.Task
    exitStatusC <-chan containerd.ExitStatus
}


포드 - 생성된 구성된 포드 인스턴스
작업 - 실행 중인 현재 프로세스 작업
exitStatusC - 종료 상태를 가져올 채널

이제 구조체를 정의한 후 Pod 생성을 위한 NewPod 메서드를 생성해 보겠습니다. 다음 함수에서 새 containerd 클라이언트, 새 컨텍스트를 만들고 이미지를 가져오고 새 ID를 생성하고 새 컨테이너를 만듭니다.

func NewPod(registryImage string, name string) (*Pod, error) {
    client, err := containerd.New("/run/containerd/containerd.sock")
    if err != nil {
        return nil, err
    }

    ctx := namespaces.WithNamespace(context.Background(), "own-kubernetes")

    image, err := client.Pull(ctx, registryImage, containerd.WithPullUnpack)
    if err != nil {
        return nil, err
    }

    id := generateNewID(name)

    container, err := client.NewContainer(
        ctx,
        id,
        containerd.WithImage(image),
        containerd.WithNewSnapshot(id+"-snapshot", image),
        containerd.WithNewSpec(oci.WithImageConfig(image)),
    )
    if err != nil {
        return nil, err
    }

    return &Pod{
        Id:        id,
        container: &container,
        ctx:       &ctx,
        client:    client,
    }, nil
}


ID 생성은 google uuid 패키지와 주어진 이름으로 생성됩니다.

func generateNewID(name string) string {
    id := uuid.New()

    return fmt.Sprintf("%s-%s", name, id)
}


다음으로 Run pod 메서드를 구현합니다. 먼저 실행 중인 pod의 프로세스가 될 새 작업을 만들고 생성을 기다렸다가 작업을 시작합니다.

func (pod *Pod) Run() (*RunningPod, error) {
    task, err := (*pod.container).NewTask(*pod.ctx, cio.NewCreator(cio.WithStdio))
    if err != nil {
        return nil, err
    }

    exitStatusC, err := task.Wait(*pod.ctx)
    if err != nil {
        fmt.Println(err)
    }

    if err := task.Start(*pod.ctx); err != nil {
        return nil, err
    }

    return &RunningPod{
        Pod:         pod,
        task:        &task,
        exitStatusC: exitStatusC,
    }, nil
}


다음으로 실행 중인 포드에 대해 Kill 메서드를 구현합니다. 기존 프로세스를 종료하고 기존 작업을 삭제한 다음 상태 코드를 반환합니다. 그리고 기존 컨테이너를 삭제하고 클라이언트 연결을 닫는 기존 포드에 대한 Delete 메서드를 구현합니다.

func (pod *RunningPod) Kill() (uint32, error) {
    // kill the process and get the exit status
    if err := (*pod.task).Kill(*pod.Pod.ctx, syscall.SIGTERM); err != nil {
        return 0, err
    }

    // wait for the process to fully exit and print out the exit status
    status := <-pod.exitStatusC
    code, _, err := status.Result()
    if err != nil {
        return 0, err
    }

    (*pod.task).Delete(*pod.Pod.ctx)

    return code, nil
}

func (pod *Pod) Delete() {
    (*pod.container).Delete(*pod.ctx, containerd.WithSnapshotCleanup)
    pod.client.Close()
}


cmd/pod.go에서 포드를 만들고 실행하기 위한 간단한 명령을 구현하고 플래그--registry--name를 정의합니다.

func init() {
    rootCmd.AddCommand(podCmd)
    podCmd.AddCommand(listCmd)

    podCmd.AddCommand(createCmd)
    createCmd.Flags().StringVar(&imageRegistry, "registry", "", "image registry to pull (required)")
    createCmd.MarkFlagRequired("registry")
    createCmd.Flags().StringVar(&name, "name", "nameless", "the pod name")
}



포드를 생성 및 실행하고 3초 후에 종료하고 삭제하기 위한 간단한 구현을 만들었습니다.

var (
    imageRegistry string
    name          string
)
var createCmd = &cobra.Command{
    Use:   "create",
    Short: "Create new pod",
    RunE: func(cmd *cobra.Command, args []string) error {
        pod, err := pod.NewPod(imageRegistry, name)
        if err != nil {
            return err
        }

        fmt.Printf("pod created: %s\n", pod.Id)
        fmt.Printf("starting pod\n")

        runningPod, err := pod.Run()
        if err != nil {
            return err
        }

        fmt.Printf("pod started: %s\n", pod.Id)

        time.Sleep(3 * time.Second)

        fmt.Printf("killing pod\n")

        code, err := runningPod.Kill()
        if err != nil {
            return err
        }
        fmt.Printf("pod killed: %s\n", pod.Id)

        fmt.Printf("%s exited with status: %d\n", runningPod.Pod.Id, code)

        pod.Delete()

        fmt.Printf("container deleted: %s\n", pod.Id)

        return nil
    },
}


그래서 포드를 생성하고 실행하는 데 필요한 모든 것을 구현했습니다. 실행되는 것을 봅시다! (containerd가 실행 중인지 확인)
터미널 빌드에서 go 프로젝트:go build main.go새 Redis 포드를 생성해 보겠습니다.

sudo ./main pod create --registry docker.io/library/redis:alpine --name redis
pod created: redis-73c4d234-2fe1-4b8f-bfe4-aa9044dc064a
starting pod
pod started: redis-73c4d234-2fe1-4b8f-bfe4-aa9044dc064a
1:C 07 Oct 2022 10:53:31.804 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 07 Oct 2022 10:53:31.804 # Redis version=7.0.5, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 07 Oct 2022 10:53:31.804 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 07 Oct 2022 10:53:31.805 # You requested maxclients of 10000 requiring at least 10032 max file descriptors.
1:M 07 Oct 2022 10:53:31.805 # Server can't set maximum open files to 10032 because of OS error: Operation not permitted.
1:M 07 Oct 2022 10:53:31.805 # Current maximum open files is 1024. maxclients has been reduced to 992 to compensate for low ulimit. If you need higher maxclients increase 'ulimit -n'.
1:M 07 Oct 2022 10:53:31.805 * monotonic clock: POSIX clock_gettime
1:M 07 Oct 2022 10:53:31.805 * Running mode=standalone, port=6379.
1:M 07 Oct 2022 10:53:31.805 # Server initialized
1:M 07 Oct 2022 10:53:31.805 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:M 07 Oct 2022 10:53:31.806 * Ready to accept connections
killing pod
1:signal-handler (1665140014) Received SIGTERM scheduling shutdown...
1:M 07 Oct 2022 10:53:34.816 # User requested shutdown...
1:M 07 Oct 2022 10:53:34.816 * Saving the final RDB snapshot before exiting.
1:M 07 Oct 2022 10:53:34.895 * DB saved on disk
1:M 07 Oct 2022 10:53:34.895 # Redis is now ready to exit, bye bye...
pod killed: redis-73c4d234-2fe1-4b8f-bfe4-aa9044dc064a
redis-73c4d234-2fe1-4b8f-bfe4-aa9044dc064a exited with status: 0
container deleted: redis-73c4d234-2fe1-4b8f-bfe4-aa9044dc064a


효과가있다!


다음 기사에서는 명령에 따라 포드를 나열하고 삭제할 것입니다.

이 부분의 전체 소스 코드 커밋은 here 찾을 수 있으며 변경 사항은 pkg/pod/pod.go 및 cmd/pod.go에 있습니다.

좋은 웹페이지 즐겨찾기