forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
client-go: Add CRUD Deployment sample
This sample adds sample code for create/list/replace/delete operations for Deployment resource for client-go library. This patch also contains documentation explaining what the example application does and how it can be executed. This patch is part of the body of work improving the client library samples. Signed-off-by: Ahmet Alp Balkan <[email protected]>
- Loading branch information
Showing
4 changed files
with
276 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
staging/src/k8s.io/client-go/examples/create-update-delete-deployment/BUILD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package(default_visibility = ["//visibility:public"]) | ||
|
||
licenses(["notice"]) | ||
|
||
load( | ||
"@io_bazel_rules_go//go:def.bzl", | ||
"go_binary", | ||
"go_library", | ||
) | ||
|
||
go_binary( | ||
name = "create-update-delete-deployment", | ||
library = ":go_default_library", | ||
tags = ["automanaged"], | ||
) | ||
|
||
go_library( | ||
name = "go_default_library", | ||
srcs = ["main.go"], | ||
tags = ["automanaged"], | ||
deps = [ | ||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", | ||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||
"//vendor/k8s.io/client-go/kubernetes:go_default_library", | ||
"//vendor/k8s.io/client-go/pkg/api/v1:go_default_library", | ||
"//vendor/k8s.io/client-go/pkg/apis/apps/v1beta1:go_default_library", | ||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library", | ||
], | ||
) |
81 changes: 81 additions & 0 deletions
81
staging/src/k8s.io/client-go/examples/create-update-delete-deployment/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# Create, Update & Delete Deployment | ||
|
||
This example program demonstrates the fundamental operations for managing on | ||
[Deployment][1] resources, such as `Create`, `List`, `Update` and `Delete`. | ||
|
||
You can adopt the source code from this example to write programs that manage | ||
other types of resources through the Kubernetes API. | ||
|
||
## Running this example | ||
|
||
Make sure you have a Kubernetes cluster and `kubectl` is configured: | ||
|
||
kubectl get nodes | ||
|
||
Compile this example on your workstation: | ||
|
||
``` | ||
cd create-update-delete-deployment | ||
go build -o ./app | ||
``` | ||
|
||
Now, run this application on your workstation with your local kubeconfig file: | ||
|
||
``` | ||
./app -kubeconfig=$HOME/.kube/config | ||
``` | ||
|
||
Running this command will execute the following operations on your cluster: | ||
|
||
1. **Create Deployment:** This will create a 2 replica Deployment. Verify with | ||
`kubectl get pods`. | ||
2. **Update Deployment:** This will update the Deployment resource created in | ||
previous step to set the replica count to 1 and add annotations. You are | ||
encouraged to inspect the retry loop that handles conflicts. Verify the new | ||
replica count and `foo=bar` annotation with `kubectl describe deployment | ||
demo`. | ||
3. **List Deployments:** This will retrieve Deployments in the `default` | ||
namespace and print their names and replica counts. | ||
4. **Delete Deployment:** This will delete the Deployment object and its | ||
dependent ReplicaSet resource. Verify with `kubectl get deployments`. | ||
|
||
Each step is separated by an interactive prompt. You must hit the | ||
<kbd>Return</kbd> key to proceeed to the next step. You can use these prompts as | ||
a break to take time to run `kubectl` and inspect the result of the operations | ||
executed. | ||
|
||
You should see an output like the following: | ||
|
||
``` | ||
Creating deployment... | ||
Created deployment "demo-deployment". | ||
-> Press Return key to continue. | ||
Updating deployment... | ||
Updated deployment... | ||
-> Press Return key to continue. | ||
Listing deployments in namespace "default": | ||
* demo-deployment (1 replicas) | ||
-> Press Return key to continue. | ||
Deleting deployment... | ||
Deleted deployment. | ||
``` | ||
|
||
## Cleanup | ||
|
||
Successfully running this program will clean the created artifacts. If you | ||
terminate the program without completing, you can clean up the created | ||
deployment with: | ||
|
||
kubectl delete deploy demo-deployment | ||
|
||
## Troubleshooting | ||
|
||
If you are getting the following error, make sure Kubernetes version of your | ||
cluster is v1.6 or above in `kubectl version`: | ||
|
||
panic: the server could not find the requested resource | ||
|
||
[1]: https://kubernetes.io/docs/user-guide/deployments/ |
165 changes: 165 additions & 0 deletions
165
staging/src/k8s.io/client-go/examples/create-update-delete-deployment/main.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/* | ||
Copyright 2017 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
// Note: the example only works with the code within the same release/branch. | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes" | ||
apiv1 "k8s.io/client-go/pkg/api/v1" | ||
appsv1beta1 "k8s.io/client-go/pkg/apis/apps/v1beta1" | ||
"k8s.io/client-go/tools/clientcmd" | ||
// Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters). | ||
// _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" | ||
) | ||
|
||
func main() { | ||
kubeconfig := flag.String("kubeconfig", "", "absolute path to the kubeconfig file") | ||
flag.Parse() | ||
if *kubeconfig == "" { | ||
panic("-kubeconfig not specified") | ||
} | ||
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) | ||
if err != nil { | ||
panic(err) | ||
} | ||
clientset, err := kubernetes.NewForConfig(config) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
deploymentsClient := clientset.AppsV1beta1().Deployments(apiv1.NamespaceDefault) | ||
|
||
deployment := &appsv1beta1.Deployment{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "demo-deployment", | ||
}, | ||
Spec: appsv1beta1.DeploymentSpec{ | ||
Replicas: int32Ptr(2), | ||
Template: apiv1.PodTemplateSpec{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Labels: map[string]string{ | ||
"app": "demo", | ||
}, | ||
}, | ||
Spec: apiv1.PodSpec{ | ||
Containers: []apiv1.Container{ | ||
{ | ||
Name: "web", | ||
Image: "nginx:1.13", | ||
Ports: []apiv1.ContainerPort{ | ||
{ | ||
Name: "http", | ||
Protocol: apiv1.ProtocolTCP, | ||
ContainerPort: 80, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
// Create Deployment | ||
fmt.Println("Creating deployment...") | ||
result, err := deploymentsClient.Create(deployment) | ||
if err != nil { | ||
panic(err) | ||
} | ||
fmt.Printf("Created deployment %q.\n", result.GetObjectMeta().GetName()) | ||
|
||
// Update Deployment | ||
prompt() | ||
fmt.Println("Updating deployment...") | ||
// You have two options to Update() this Deployment: | ||
// | ||
// 1. Modify the "deployment" variable and call: Update(deployment). | ||
// This works like the "kubectl replace" command and it overwrites/loses changes | ||
// made by other clients between you Create() and Update() the object. | ||
// 2. Modify the "result" returned by Create()/Get() and retry Update(result) until | ||
// you no longer get a conflict error. This way, you can preserve changes made | ||
// by other clients between Create() and Update(). This is implemented below: | ||
|
||
for { | ||
result.Spec.Replicas = int32Ptr(1) // reduce replica count | ||
result.Spec.Template.Annotations = map[string]string{ // add annotations | ||
"foo": "bar", | ||
} | ||
|
||
if _, err := deploymentsClient.Update(result); errors.IsConflict(err) { | ||
// Deployment is modified in the meanwhile, query the latest version | ||
// and modify the retrieved object. | ||
fmt.Println("encountered conflict, retrying") | ||
result, err = deploymentsClient.Get("demo-deployment", metav1.GetOptions{}) | ||
if err != nil { | ||
panic(fmt.Errorf("Get failed: %+v", err)) | ||
} | ||
} else if err != nil { | ||
panic(err) | ||
} else { | ||
break | ||
} | ||
|
||
// TODO: You should sleep here with an exponential backoff to avoid | ||
// exhausting the apiserver, and add a limit/timeout on the retries to | ||
// avoid getting stuck in this loop indefintiely. | ||
} | ||
fmt.Println("Updated deployment...") | ||
|
||
// List Deployments | ||
prompt() | ||
fmt.Printf("Listing deployments in namespace %q:\n", apiv1.NamespaceDefault) | ||
list, err := deploymentsClient.List(metav1.ListOptions{}) | ||
if err != nil { | ||
panic(err) | ||
} | ||
for _, d := range list.Items { | ||
fmt.Printf(" * %s (%d replicas)\n", d.Name, *d.Spec.Replicas) | ||
} | ||
|
||
// Delete Deployment | ||
prompt() | ||
fmt.Println("Deleting deployment...") | ||
deletePolicy := metav1.DeletePropagationForeground | ||
if err := deploymentsClient.Delete("demo-deployment", &metav1.DeleteOptions{ | ||
PropagationPolicy: &deletePolicy, | ||
}); err != nil { | ||
panic(err) | ||
} | ||
fmt.Println("Deleted deployment.") | ||
} | ||
|
||
func prompt() { | ||
fmt.Printf("-> Press Return key to continue.") | ||
scanner := bufio.NewScanner(os.Stdin) | ||
for scanner.Scan() { | ||
break | ||
} | ||
if err := scanner.Err(); err != nil { | ||
panic(err) | ||
} | ||
fmt.Println() | ||
} | ||
|
||
func int32Ptr(i int32) *int32 { return &i } |