Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go design theory learned from Kubernetes

Go design theory learned from Kubernetes

Avatar for Takamichi Omori

Takamichi Omori

April 24, 2021
Tweet

More Decks by Takamichi Omori

Other Decks in Programming

Transcript

  1. ©2021 Wantedly, Inc. Takamichi Omori @onsd_ DX Squad Intern, Wantedly,

    Inc. Love Kubernetes, Go, etc *BN 2 https://www.wantedly.com/id/onsd_
  2. ©2021 Wantedly, Inc. /42 ࠓ೔࿩͢͜ͱ ,VCFSOFUFT͔ΒֶΜͩ(Pͷઃܭ࿦ 5 ࣮ྫɿCustom Controller ͷ࣮૷͔ΒֶΜͩઃܭ࿦

    • Package Λ෼͚ͯॲཧΛΘ͔Γ΍͘͢͢Δํ๏ • εφοϓγϣοτςετʹ͍ͭͯ
  3. ©2021 Wantedly, Inc. /42 $VTUPN$POUSPMMFSͱ͸ ,VCFSOFUFTΛ֦ு͢Δ࢓૊ΈͷҰͭ https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ 7 Kubernetes ʹ͸

    Deployment, Service ͷΑ͏ʹͨ͘͞ΜͷϦιʔε͕ଘࡏ͢Δ Custom Controller ͸ɺಠࣗʹઃܭͨ͠ϦιʔεΛίϯτϩʔϧ͢ΔͨΊͷΞϓϦέʔγϣϯ
  4. ©2021 Wantedly, Inc. /42 ૉ௚ʹॻ͍͍ͯͬͨ৔߹ 3FDPODJMFʹ͢΂ͯΛॻ͘ੈք 1. ཧ૝తͳϦιʔεͷঢ়ଶΛܭࢉ 2. ࠩ෼͕͋Δ৔߹͸ߋ৽

    3. ඞཁ͕ͳ͘ͳͬͨϦιʔε͕͋Δ৔߹͸ফ͢ 
 ࠓճͷྫͩͱɺෳ਺ͷϦιʔεΛ࡞੒ɾߋ৽ɾ࡟আ 
 ͢Δඞཁ͕͋ͬͨ 13
  5. ©2021 Wantedly, Inc. /42 6QEBUFSͷJOUFSGBDF 6QEBUFS 17 // type NamespacedName

    struct { / / Namespace strin g / / Name strin g // } type Updater interface { Update(ctx context.Context, 
 slug types.NamespacedName) erro r / / ListOption is used specify namespac e UpdateAll(ctx context.Context, opts ...client.ListOption) erro r }
  6. ©2021 Wantedly, Inc. /42 3FGSFTIFSͷJOUFSGBDF 3FGSFTIFS 20 ࣮ࡍ͸ϨΠϠʔͱ͍͏ΑΓϥΠϒϥϦ // util.Object

    represents Kubernetes Resourc e type Refresher interface { Refresh(ctx context.Context , parent util.Object, children []util.Object) erro r }
  7. ©2021 Wantedly, Inc. /42 3FGSFTIFS͕͋ΔͱԿ͕خ͍͠ͷ͔ ໰୊ͷ؆ུԽ ཧ૝ঢ়ଶΛड͚औΓɺෆཁͳϦιʔε͸࡟আ͢Δ RefresherΛಋೖ͢Δ͜ͱͰ 
 UpdaterΛ࣮૷͢Δࡍʹඞཁͳͷ͸ɺཧ૝తͳ

    ϦιʔεͷϦετΛ࡞Δॲཧ͚ͩʹͳͬͨ 21 ॲཧͷڞ௨Խ Ϧιʔεʹ਌ࢠؔ܎͕͋Δ৔߹ɺRefresherΛ 
 ࢖͏͜ͱͰॲཧͷڞ௨Խ͕Ͱ͖Δ
  8. ©2021 Wantedly, Inc. /42 3FGSFTIFS͕ݱঢ়Λཧ૝ʹ͚ۙͮΔํ๏ ࡟আ͢ΔϦιʔεͷಛఆ Refresher ͸ɺ਌Ϧιʔεͱཧ૝తͳࢠϦιʔεͷ 
 ϦετΛड͚औΔ

    ਌Ϧιʔε͔Β͢Ͱʹଘࡏ͢ΔࢠϦιʔεΛಛఆ͠ɺ 
 ड͚औͬͨϦιʔεͱൺֱ͢Δ͜ͱͰ࡟আ͢Δ΂͖ 
 ϦιʔεΛಛఆͰ͖Δ ਌ࢠؔ܎ͷ੍໿ ͋ΔϦιʔε͸ඞͣ਌ϦιʔεΛ࣋ͭͱ͍͏੍໿ 22
  9. ©2021 Wantedly, Inc. /42 ,VCFSOFUFT্Ͱ਌ࢠؔ܎Λࣔ͢ํ๏ 0XOFS3FGFSFODF 23 Ϧιʔεʹ͍ͭͯɺͦͷΦʔφʔϦιʔεΛࣔ͢ϑΟʔϧυ OwnerReference ͷϝϦοτ

    Owner ͕ফ͑ͨͱ͖ʹGC ͕ࢠϦιʔεΛফͯ͘͠ΕΔ πϦʔߏ଄Λ࣋ͭϦιʔεΛ؅ཧ͢Δͱ͖͚͓ͭͯ͘ͱศར
  10. ©2021 Wantedly, Inc. /42 #VJMEFSͷJOUFSGBDF #VJMEFS • ͋ΔϦιʔεʹ͍ͭͯɺཧ૝తͳঢ়ଶΛܭࢉ͢Δ • ܭࢉͨ݁͠ՌΛRefresherʹΘͨ͢

    25 // util.Object represents Kubernetes Resourc e type Builder interface { Build(ctx context.Context) ([]util.Object, error ) }
  11. ©2021 Wantedly, Inc. /42 ϨΠϠʔ෼͚ͷ۩ମྫ 27 // type virtualServiceUpdater struct

    { // client client.Clien t // log logr.Logge r // scheme *runtime.Schem e // } func (r virtualServiceUpdater) Update(ctx context.Context,
 serviceSlug types.NamespacedName) error { service := &corev1.Service{ } if err := r.client.Get(ctx, serviceSlug, service); err != nil { return errors.WithStack(err ) } objList, err := lister.
 NewVirtualServiceBuilder(r.client, serviceSlug).Build(ctx ) if err != nil { return errors.WithStack(err ) } ref := refresh.New(r.client, r.scheme ) if err := ref.Refresh(ctx, service, objList); err != nil { return errors.WithStack(err ) } return ni l }
  12. ©2021 Wantedly, Inc. /42 VirtualServiceUpdater ͋Δ service ʹඥͮ͘ 
 virtualService

    Λ࡞੒͢Δ 
 Updater ϨΠϠʔ෼͚ͷ۩ମྫ 28 // type virtualServiceUpdater struct { // client client.Clien t // log logr.Logge r // scheme *runtime.Schem e // } func (r virtualServiceUpdater) Update(ctx context.Context,
 serviceSlug types.NamespacedName) error { service := &corev1.Service{ } if err := r.client.Get(ctx, serviceSlug, service); err != nil { return errors.WithStack(err ) } objList, err := lister.
 NewVirtualServiceBuilder(r.client, serviceSlug).Build(ctx ) if err != nil { return errors.WithStack(err ) } ref := refresh.New(r.client, r.scheme ) if err := ref.Refresh(ctx, service, objList); err != nil { return errors.WithStack(err ) } return ni l }
  13. ©2021 Wantedly, Inc. /42 VirtualServiceUpdater ͋Δ service ʹඥͮ͘ 
 virtualService

    Λ࡞੒͢Δ 
 Updater ϨΠϠʔ෼͚ͷ۩ମྫ 29 // type virtualServiceUpdater struct { // client client.Clien t // log logr.Logge r // scheme *runtime.Schem e // } func (r virtualServiceUpdater) Update(ctx context.Context,
 serviceSlug types.NamespacedName) error { service := &corev1.Service{ } if err := r.client.Get(ctx, serviceSlug, service); err != nil { return errors.WithStack(err ) } objList, err := lister.
 NewVirtualServiceBuilder(r.client, serviceSlug).Build(ctx ) if err != nil { return errors.WithStack(err ) } ref := refresh.New(r.client, r.scheme ) if err := ref.Refresh(ctx, service, objList); err != nil { return errors.WithStack(err ) } return ni l } VirtualServiceBuilder VirtualServiceʹ͍ͭͯɺ 
 ཧ૝తͳঢ়ଶΛ࡞Δ Builder
  14. ©2021 Wantedly, Inc. /42 VirtualServiceUpdater ͋Δ service ʹඥͮ͘ 
 virtualService

    Λ࡞੒͢Δ 
 Updater ϨΠϠʔ෼͚ͷ۩ମྫ 30 // type virtualServiceUpdater struct { // client client.Clien t // log logr.Logge r // scheme *runtime.Schem e // } func (r virtualServiceUpdater) Update(ctx context.Context,
 serviceSlug types.NamespacedName) error { service := &corev1.Service{ } if err := r.client.Get(ctx, serviceSlug, service); err != nil { return errors.WithStack(err ) } objList, err := lister.
 NewVirtualServiceBuilder(r.client, serviceSlug).Build(ctx ) if err != nil { return errors.WithStack(err ) } ref := refresh.New(r.client, r.scheme ) if err := ref.Refresh(ctx, service, objList); err != nil { return errors.WithStack(err ) } return ni l } VirtualServiceBuilder VirtualServiceʹ͍ͭͯɺ 
 ཧ૝తͳঢ়ଶΛ࡞Δ Builder Refresher ϦιʔεͷϦετΛड͚औΓ 
 Ϋϥελͷঢ়ଶΛ߹ΘͤΔ
  15. ©2021 Wantedly, Inc. /42 ϨΠϠʔ෼͚ͷ۩ମྫ 31 // type virtualServiceUpdater struct

    { // client client.Clien t // log logr.Logge r // scheme *runtime.Schem e // } func (r virtualServiceUpdater) Update(ctx context.Context,
 serviceSlug types.NamespacedName) error { service := &corev1.Service{ } if err := r.client.Get(ctx, serviceSlug, service); err != nil { return errors.WithStack(err ) } objList, err := lister.
 NewVirtualServiceBuilder(r.client, serviceSlug).Build(ctx ) if err != nil { return errors.WithStack(err ) } ref := refresh.New(r.client, r.scheme ) if err := ref.Refresh(ctx, service, objList); err != nil { return errors.WithStack(err ) } return ni l } VirtualServiceUpdater ͋Δ service ʹඥͮ͘ 
 virtualService Λ࡞੒͢Δ 
 Updater VirtualServiceBuilder VirtualServiceʹ͍ͭͯɺ 
 ཧ૝తͳঢ়ଶΛ࡞Δ Builder Refresher ϦιʔεͷϦετΛड͚औΓ 
 Ϋϥελͷঢ়ଶΛ߹ΘͤΔ
  16. ©2021 Wantedly, Inc. /42 ςετͷ໨త ςετͰ͔֬Ί͍ͨ͜ͱ͸ʁ ద੾ͳKubernetesͷObject͕࡞੒͞ΕΔ͔Ͳ͏͔ • Builder •

    ͋ΔϦιʔε͕ଘࡏ͍ͯ͠Δͱ͖ʹɺద੾ͳϦιʔε͕࡞੒͞ΕΔ͔͔֬Ί͍ͨ • Refresher • ͋ΔϦιʔε͕ଘࡏ͍ͯ͠Δͱ͖ʹɺड͚औͬͨϦιʔεͰΫϥελͷঢ়ଶΛมߋ͍ͨ͠ • มߋ͞ΕͨΫϥελͷঢ়ଶ͕ཧ૝తͰ͋Δ͔͔֬Ί͍ͨ 33
  17. ©2021 Wantedly, Inc. /42 4OBQTIPUςετ $VQBMPZΛ࢖ͬͨTOBQTIPUςετ • Kubernetes ͷ Object

    List ͷ snapshot ΛࡱΓɺ yaml ͱͯ͠อଘ͢Δ • Yaml ͷࠩ෼͸ github ্Ͱ΋มߋ͕Θ͔Γ΍͍͢ͷͰɺReview΋͠΍͍͢ Controller ʹมߋΛՃ͑Δͱ͖ 1. ݱঢ়ͷڍಈΛอଘ͢Δ 2. มߋΛՃ͑ɺεφοϓγϣοτΛߋ৽͢Δ • ૝ఆ͍ͯ͠ΔڍಈΛ͍ͯ͠Δ͔Ͳ͏͔Λ͔֬ΊΔ https://github.com/bradleyjkemp/cupaloy 34
  18. ©2021 Wantedly, Inc. /42 4OBQTIPUςετ $VQBMPZΛ࢖ͬͨTOBQTIPUςετ • Kubernetes ͷ Object

    List ͷ snapshot ΛࡱΓɺ yaml ͱͯ͠อଘ͢Δ • Yaml ͷࠩ෼͸ github ্Ͱ΋มߋ͕Θ͔Γ΍͍͢ͷͰɺReview΋͠΍͍͢ Controller ʹมߋΛՃ͑Δͱ͖ 1. ςετ͕ͳ͚Ε͹௥Ճ • ݱঢ়ͷڍಈΛอଘ͓ͯ͘͠ 2. มߋΛՃ͑ɺςετ͢Δ • ૝ఆ͍ͯ͠ΔڍಈΛ͍ͯ͠Δ͔Ͳ͏͔Λ͔֬ΊΔ https://github.com/bradleyjkemp/cupaloy 35
  19. ©2021 Wantedly, Inc. /42 6QEBUFSʹ͓͚Δ4OBQTIPUςετͷྫ 36 t.Run(testcase.name, func(t *testing.T) {

    existingResources := testcase.initialStat e clnt := fake.NewFakeClientWithScheme(scheme, existingResources... ) up := updater.NewVirtualServiceUpdater(clnt, ctrl.Log, scheme ) ctx := context.Background( ) err := up.UpdateAll(ctx, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } vsl := &istio.VirtualServiceList{ } err = clnt.List(ctx, vsl, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } ut.SnapshotYaml(t, vsl ) })
  20. ©2021 Wantedly, Inc. /42 6QEBUFSʹ͓͚Δ4OBQTIPUςετͷྫ 37 t.Run(tc.name, func(t *testing.T) {

    existingResources := tc.initialStat e clnt := fake.NewFakeClientWithScheme(scheme, existingResources... ) up := updater.NewVirtualServiceUpdater(clnt, ctrl.Log, scheme ) ctx := context.Background( ) err := up.UpdateAll(ctx, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } vsl := &istio.VirtualServiceList{ } err = clnt.List(ctx, vsl, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } ut.SnapshotYaml(t, vsl ) } ) ςετͷͨΊͷઃఆ
  21. ©2021 Wantedly, Inc. /42 6QEBUFSʹ͓͚Δ4OBQTIPUςετͷྫ 38 t.Run(tc.name, func(t *testing.T) {

    existingResources := tc.initialStat e clnt := fake.NewFakeClientWithScheme(scheme, existingResources... ) up := updater.NewVirtualServiceUpdater(clnt, ctrl.Log, scheme ) ctx := context.Background() err := up.UpdateAll(ctx, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } vsl := &istio.VirtualServiceList{ } err = clnt.List(ctx, vsl, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } ut.SnapshotYaml(t, vsl ) } ) ςετͷͨΊͷઃఆ ؔ਺Λ࣮ߦ
  22. ©2021 Wantedly, Inc. /42 6QEBUFSʹ͓͚Δ4OBQTIPUςετͷྫ 39 t.Run(tc.name, func(t *testing.T) {

    existingResources := tc.initialStat e clnt := fake.NewFakeClientWithScheme(scheme, existingResources... ) up := updater.NewVirtualServiceUpdater(clnt, ctrl.Log, scheme ) ctx := context.Background( ) err := up.UpdateAll(ctx, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } vsl := &istio.VirtualServiceList{ } err = clnt.List(ctx, vsl, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } ut.SnapshotYaml(t, vsl ) } ) ςετͷͨΊͷઃఆ ؔ਺Λ࣮ߦ ݁ՌΛऔಘ
  23. ©2021 Wantedly, Inc. /42 6QEBUFSʹ͓͚Δ4OBQTIPUςετͷྫ 40 t.Run(tc.name, func(t *testing.T) {

    existingResources := tc.initialStat e clnt := fake.NewFakeClientWithScheme(scheme, existingResources... ) up := updater.NewVirtualServiceUpdater(clnt, ctrl.Log, scheme ) ctx := context.Background( ) err := up.UpdateAll(ctx, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } vsl := &istio.VirtualServiceList{ } err = clnt.List(ctx, vsl, &client.ListOptions{Namespace: "some-namespace"} ) if err != nil { t.Fatal(err ) } ut.SnapshotYaml(t, vsl) // make objectList to string and take snapsho t } ) ςετͷͨΊͷઃఆ ؔ਺Λ࣮ߦ ݁ՌΛऔಘ औಘͨ݁͠ՌΛอଘ
  24. ©2021 Wantedly, Inc. /42 4OBQTIPUςετͷϝϦοτɾσϝϦοτ ˓ؾܰʹςετ͕Ͱ͖Δ มߋ͢ΔՕॴͷϦετΛऔಘͯ͠อଘ͢Δ͚ͩ 
 ·ͨɺऔಘͷॲཧ΋͕͔͔࣌ؒΒͳ͍ͷͰಋೖ͸͠΍͍͢ ✕4OBQTIPU͕େྔʹอଘ͞ΕΔ

    ໢ཏతʹ͢Δͱsnapshot ͕େྔʹͳͬͯ PR ͕ٯʹݟͮΒ͘ͳΔ 
 ૝ఆ֎ͷͱ͜Ζʹ diff ͕ग़Δͱ൑ఆ͕೉͘͠ͳΔ ˓ͲΜͲΜ࣮૷͍͚ͯ͠Δ ؾܰʹςετ͕Ͱ͖ΔͷͰͲΜͲΜ࣮૷͍ͯ͘͠ϑΣʔζʹ޲͍͍ͯΔ ࢓༷͕มΘͬͨͱ͖ʹ snapshot ʹࠩ෼͕ͰΔͷͰΘ͔Γ΍͍͢ 41
  25. ©2021 Wantedly, Inc. /42 42 Kubernetes ͔ΒֶΜͩ Go ͷઃܭ࿦ ෳࡶͳ໰୊͸؆୯ͳ໰୊ʹ੾Γग़ͦ͏

    Custom Controller Λ࡞Δ্Ͱ௚໘͕ͪ͠ͳ໰୊ͱͦͷղܾ ΄͍͠Ϧιʔεͷ࡞੒ͱΫϥελͷঢ়ଶͷߋ৽ΛΘ͚Δͱ͏·͍͘͘ ద੾ͳ package ෼͚͸΍͸Γେࣄ Wantedly Ͱ͸ Go ΋࢖ΘΕ͍ͯ·͢ ϓϩμΫγϣϯͷΞϓϦέʔγϣϯ͔Βɺࣾ಺πʔϧ·Ͱ ·ͱΊ ॲཧΛ࠶ར༻Ͱ͖Δ͘͠ΈΛͭ͘Ζ͏