최근 k8s에 Resilience를 테스트 하면서 이녀석을 사용해 보았다. 여러 Faults를 제공하는데 특히 pod에 장애를 주입시키는 것을 중점적으로 테스트 해보려고 했다.
https://github.com/chaos-mesh/chaos-mesh
Pod Faults는 3가지 동작방식을 지원합니다
- pod-failure
- pod-kill
- container-kill
각 동작은 Chaos Daemon에서 Controller Manager의 호출을 받아 수행됩니다. 동작은 아래의 코드에서 수행됩니다.
https://github.com/chaos-mesh/chaos-mesh/tree/master/controllers/chaosimpl/podchaos
각 Container는 Daemon에서 Runtime별로 Socket을 열어 통신합니다. 따라서, Chaos Daemon은 각 Container와 직접적으로 통신하며 PID를 제어합니다
func V1() ([]cgroups.Subsystem, error) {
subsystems, err := defaults("/host-sys/fs/cgroup")
if err != nil {
return nil, err
}
var enabled []cgroups.Subsystem
for _, s := range pathers(subsystems) {
// check and remove the default groups that do not exist
if _, err := os.Lstat(s.Path("/")); err == nil {
enabled = append(enabled, s)
}
}
return enabled, nil
}
func PidPath(pid int) cgroups.Path {
p := fmt.Sprintf("/proc/%d/cgroup", pid)
paths, err := cgroups.ParseCgroupFile(p)
if err != nil {
return func(_ cgroups.Name) (string, error) {
return "", errors.Wrapf(err, "parse cgroup file %s", p)
}
}
return func(name cgroups.Name) (string, error) {
root, ok := paths[string(name)]
if !ok {
if root, ok = paths["name="+string(name)]; !ok {
return "", errors.New("controller is not supported")
}
}
return root, nil
}
}
실제로 위의 코드를 통해 Daemon에서 cgroup단위로 컨트롤 하기 때문에 여러가지 스트레스를 각 Pod에 주입할 수 있습니다.
https://github.com/chaos-mesh/chaos-mesh/tree/master/pkg/chaosdaemon
Container-kill
해당 엑션을 수행하면 Chaos Daemon에서 ContainerKill function을 실행시켜 특정 Container ID를 가져와 해당 컨테이너를 stop 시킵니다.
func (b *ChaosDaemonClientBuilder) Build(ctx context.Context, pod *v1.Pod) (chaosdaemonclient.ChaosDaemonClientInterface, error) {
...
daemonIP, err := b.FindDaemonIP(ctx, pod)
if err != nil {
return nil, err
}
builder := grpcUtils.Builder(daemonIP, config.ControllerCfg.ChaosDaemonPort).WithDefaultTimeout()
if config.ControllerCfg.TLSConfig.ChaosMeshCACert != "" {
builder.TLSFromFile(config.ControllerCfg.TLSConfig.ChaosMeshCACert, config.ControllerCfg.TLSConfig.ChaosDaemonClientCert, config.ControllerCfg.TLSConfig.ChaosDaemonClientKey)
} else {
builder.Insecure()
}
cc, err := builder.Build()
if err != nil {
return nil, err
}
return chaosdaemonclient.New(cc), nil
}
PodFailure
정상인 Pod의 Image를 Chaos mesh에서 만든 비정상 이미지로 변경하여 고의적으로 Pod를 Fail로 처리합니다
func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
...
pod := origin.DeepCopy()
for index := range pod.Spec.Containers {
originImage := pod.Spec.Containers[index].Image
name := pod.Spec.Containers[index].Name
key := annotation.GenKeyForImage(podchaos, name, false)
if pod.Annotations == nil {
pod.Annotations = make(map[string]string)
}
// If the annotation is already existed, we could skip the reconcile for this container
if _, ok := pod.Annotations[key]; ok {
continue
}
pod.Annotations[key] = originImage
pod.Spec.Containers[index].Image = config.ControllerCfg.PodFailurePauseImage
}
for index := range pod.Spec.InitContainers {
originImage := pod.Spec.InitContainers[index].Image
name := pod.Spec.InitContainers[index].Name
key := annotation.GenKeyForImage(podchaos, name, true)
if pod.Annotations == nil {
pod.Annotations = make(map[string]string)
}
// If the annotation is already existed, we could skip the reconcile for this container
if _, ok := pod.Annotations[key]; ok {
continue
}
pod.Annotations[key] = originImage
pod.Spec.InitContainers[index].Image = config.ControllerCfg.PodFailurePauseImage
}
err = impl.Patch(ctx, pod, client.MergeFrom(&origin))
if err != nil {
// TODO: handle this error
return v1alpha1.NotInjected, err
}
return v1alpha1.Injected, nil
}
PodKill
terminationGracePeriodSeconds 기능을 사용하여 Pod를 종료 시킵니다
import (
"context"
v1 "k8s.io/api/core/v1"=
"sigs.k8s.io/controller-runtime/pkg/client"
)
type Impl struct {
client.Client
}
func (impl *Impl) Apply(ctx context.Context, index int, records []*v1alpha1.Record, obj v1alpha1.InnerObject) (v1alpha1.Phase, error) {
...
err = impl.Get(ctx, namespacedName, &pod)
if err != nil {
// TODO: handle this error
return v1alpha1.NotInjected, err
}
err = impl.Delete(ctx, &pod, &client.DeleteOptions{
GracePeriodSeconds: &podchaos.Spec.GracePeriod, // PeriodSeconds has to be set specifically
})
...
return v1alpha1.Injected, nil
}
코드를 분석한 내용이다. 위와같은 코드를 실행시켜서 실제 커널영역을 컨트롤 한다.
'Server Infra > Kubernetes' 카테고리의 다른 글
PKOS 2기 2주차 - k8s network(feat. EKS) (0) | 2023.03.12 |
---|---|
PKOS 2기 1주차 - kops (0) | 2023.03.06 |
EKS 쉽게 만드려고 삽질하는중 (1) | 2022.09.19 |
K8s Study DOIK - MySQL Operator for Kubernetes #2 (0) | 2022.06.05 |
K8s Study DOIK - MySQL Operator for Kubernetes (0) | 2022.06.05 |