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

Go design theory learned from Kubernetes

Go design theory learned from Kubernetes

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 ΋࢖ΘΕ͍ͯ·͢ ϓϩμΫγϣϯͷΞϓϦέʔγϣϯ͔Βɺࣾ಺πʔϧ·Ͱ ·ͱΊ ॲཧΛ࠶ར༻Ͱ͖Δ͘͠ΈΛͭ͘Ζ͏