You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by ka...@apache.org on 2021/04/22 05:48:30 UTC
[submarine] branch master updated: SUBMARINE-799. Create a
submarine-server for a single user
This is an automated email from the ASF dual-hosted git repository.
kaihsun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git
The following commit(s) were added to refs/heads/master by this push:
new 860c043 SUBMARINE-799. Create a submarine-server for a single user
860c043 is described below
commit 860c04301a806466d261ecee7d3e8cb4a58bec0a
Author: kevin85421 <b0...@ntu.edu.tw>
AuthorDate: Thu Apr 22 13:48:21 2021 +0800
SUBMARINE-799. Create a submarine-server for a single user
### What is this PR for?
Create a submarine server for a single user via the submarine operator.
Reference: https://github.com/apache/submarine/blob/master/helm-charts/submarine/templates/submarine-server.yaml
### What type of PR is it?
[Feature]
### Todos
### What is the Jira issue?
https://issues.apache.org/jira/browse/SUBMARINE-799
### How should this be tested?
https://user-images.githubusercontent.com/20109646/115583344-62eba200-a2fc-11eb-90d2-72acc9d13938.mov
### Screenshots (if appropriate)
* service/submarine-server (submarine-operator)
<img width="414" alt="截圖 2021-04-21 下午11 41 37" src="https://user-images.githubusercontent.com/20109646/115583500-86aee800-a2fc-11eb-8ee2-04391cdf5ce0.png">
* service/submarine-server (helm)
<img width="794" alt="截圖 2021-04-21 下午11 47 56" src="https://user-images.githubusercontent.com/20109646/115583717-bb22a400-a2fc-11eb-99e9-c00ba505dbe6.png">
* serviceaccount/submarine-server (submarine-operator)
<img width="447" alt="截圖 2021-04-21 下午11 41 42" src="https://user-images.githubusercontent.com/20109646/115583564-96c6c780-a2fc-11eb-9343-60fbb5cee049.png">
* serviceaccount/submarine-server (helm)
<img width="804" alt="截圖 2021-04-21 下午11 48 19" src="https://user-images.githubusercontent.com/20109646/115583796-cd9cdd80-a2fc-11eb-8a1b-d7ec76c6c41c.png">
* deployment/submarine-server (submarine-operator)
<img width="824" alt="截圖 2021-04-21 下午11 41 51" src="https://user-images.githubusercontent.com/20109646/115583632-a6461080-a2fc-11eb-9875-d187499de27c.png">
* deployment/submarine-server (helm)
<img width="886" alt="截圖 2021-04-21 下午11 48 49" src="https://user-images.githubusercontent.com/20109646/115583870-dd1c2680-a2fc-11eb-8404-f849afad9f2a.png">
### Questions:
* Do the license files need updating? No
* Are there breaking changes for older versions? No
* Does this need new documentation? No
---
submarine-cloud-v2/controller.go | 220 ++++++++++++++++++++++++++++++++-------
submarine-cloud-v2/main.go | 16 +--
2 files changed, 189 insertions(+), 47 deletions(-)
diff --git a/submarine-cloud-v2/controller.go b/submarine-cloud-v2/controller.go
index 30d686a..3ddd821 100644
--- a/submarine-cloud-v2/controller.go
+++ b/submarine-cloud-v2/controller.go
@@ -18,26 +18,33 @@
package main
import (
+ "context"
"encoding/json"
"fmt"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ clientset "submarine-cloud-v2/pkg/generated/clientset/versioned"
+ submarinescheme "submarine-cloud-v2/pkg/generated/clientset/versioned/scheme"
+ informers "submarine-cloud-v2/pkg/generated/informers/externalversions/submarine/v1alpha1"
+ listers "submarine-cloud-v2/pkg/generated/listers/submarine/v1alpha1"
+ "time"
+
+ appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/util/intstr"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
appsinformers "k8s.io/client-go/informers/apps/v1"
+ coreinformers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+ appslisters "k8s.io/client-go/listers/apps/v1"
+ corelisters "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
- clientset "submarine-cloud-v2/pkg/generated/clientset/versioned"
- submarinescheme "submarine-cloud-v2/pkg/generated/clientset/versioned/scheme"
- "submarine-cloud-v2/pkg/helm"
- informers "submarine-cloud-v2/pkg/generated/informers/externalversions/submarine/v1alpha1"
- listers "submarine-cloud-v2/pkg/generated/listers/submarine/v1alpha1"
- "time"
)
const controllerAgentName = "submarine-controller"
@@ -52,6 +59,9 @@ type Controller struct {
submarinesLister listers.SubmarineLister
submarinesSynced cache.InformerSynced
+ deploymentLister appslisters.DeploymentLister
+ serviceaccountLister corelisters.ServiceAccountLister
+ serviceLister corelisters.ServiceLister
// workqueue is a rate limited work queue. This is used to queue work to be
// processed instead of performing it as soon as a change happens. This
// means we can ensure we only process a fixed amount of resources at a
@@ -68,6 +78,8 @@ func NewController(
kubeclientset kubernetes.Interface,
submarineclientset clientset.Interface,
deploymentInformer appsinformers.DeploymentInformer,
+ serviceInformer coreinformers.ServiceInformer,
+ serviceaccountInformer coreinformers.ServiceAccountInformer,
submarineInformer informers.SubmarineInformer) *Controller {
// TODO: Create event broadcaster
@@ -82,12 +94,15 @@ func NewController(
// Initialize controller
controller := &Controller{
- kubeclientset: kubeclientset,
- submarineclientset: submarineclientset,
- submarinesLister: submarineInformer.Lister(),
- submarinesSynced: submarineInformer.Informer().HasSynced,
- workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Submarines"),
- recorder: recorder,
+ kubeclientset: kubeclientset,
+ submarineclientset: submarineclientset,
+ submarinesLister: submarineInformer.Lister(),
+ submarinesSynced: submarineInformer.Informer().HasSynced,
+ deploymentLister: deploymentInformer.Lister(),
+ serviceLister: serviceInformer.Lister(),
+ serviceaccountLister: serviceaccountInformer.Lister(),
+ workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Submarines"),
+ recorder: recorder,
}
// Setting up event handler for Submarine
@@ -117,34 +132,6 @@ func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
return fmt.Errorf("failed to wait for caches to sync")
}
- // Example: HelmInstall (can be removed in the future):
- // This is equal to:
- // helm repo add k8s-as-helm https://ameijer.github.io/k8s-as-helm/
- // . helm repo update
- // helm install helm-install-example-release k8s-as-helm/svc --set ports[0].protocol=TCP,ports[0].port=80,ports[0].targetPort=9376
- // Useful Links:
- // (1) https://github.com/PrasadG193/helm-clientgo-example
- // . (2) https://github.com/ameijer/k8s-as-helm/tree/master/charts/svc
- klog.Info("[Helm example] Install")
- helmActionConfig := helm.HelmInstall(
- "https://ameijer.github.io/k8s-as-helm/",
- "k8s-as-helm",
- "svc",
- "helm-install-example-release",
- "default",
- map[string]string {
- "set": "ports[0].protocol=TCP,ports[0].port=80,ports[0].targetPort=9376",
- },
- )
-
- klog.Info("[Helm example] Sleep 60 seconds")
- time.Sleep(time.Duration(60) * time.Second)
-
- klog.Info("[Helm example] Uninstall")
- helm.HelmUninstall("helm-install-example-release", helmActionConfig)
-
-
-
klog.Info("Starting workers")
// Launch two workers to process Submarine resources
for i := 0; i < threadiness; i++ {
@@ -193,6 +180,147 @@ func (c *Controller) processNextWorkItem() bool {
return true
}
+// newSubmarineServer is a function to create submarine-server.
+// Reference: https://github.com/apache/submarine/blob/master/helm-charts/submarine/templates/submarine-server.yaml
+func (c *Controller) newSubmarineServer(serverImage string, serverReplicas int32, namespace string) error {
+ klog.Info("[newSubmarineServer]")
+ serverName := "submarine-server"
+
+ // Step1: Create ServiceAccount
+ serviceaccount, serviceaccount_err := c.serviceaccountLister.ServiceAccounts(namespace).Get(serverName)
+ // If the resource doesn't exist, we'll create it
+ if errors.IsNotFound(serviceaccount_err) {
+ serviceaccount, serviceaccount_err = c.kubeclientset.CoreV1().ServiceAccounts(namespace).Create(context.TODO(),
+ &corev1.ServiceAccount{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: serverName,
+ },
+ },
+ metav1.CreateOptions{})
+ klog.Info(" Create ServiceAccount: ", serviceaccount.Name)
+ }
+
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if serviceaccount_err != nil {
+ return serviceaccount_err
+ }
+
+ // TODO: (sample-controller) controller.go:287 ~ 293
+
+ // Step2: Create Service
+ service, service_err := c.serviceLister.Services(namespace).Get(serverName)
+ // If the resource doesn't exist, we'll create it
+ if errors.IsNotFound(service_err) {
+ service, service_err = c.kubeclientset.CoreV1().Services(namespace).Create(context.TODO(),
+ &corev1.Service{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: serverName,
+ Labels: map[string]string{
+ "run": serverName,
+ },
+ },
+ Spec: corev1.ServiceSpec{
+ Ports: []corev1.ServicePort{
+ {
+ Port: 8080,
+ TargetPort: intstr.FromInt(8080),
+ Protocol: "TCP",
+ },
+ },
+ Selector: map[string]string{
+ "run": serverName,
+ },
+ },
+ },
+ metav1.CreateOptions{})
+ klog.Info(" Create Service: ", service.Name)
+ }
+
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if service_err != nil {
+ return service_err
+ }
+
+ // TODO: (sample-controller) controller.go:287 ~ 293
+
+ // Step3: Create Deployment
+ deployment, deployment_err := c.deploymentLister.Deployments(namespace).Get(serverName)
+ // If the resource doesn't exist, we'll create it
+ if errors.IsNotFound(deployment_err) {
+ deployment, deployment_err = c.kubeclientset.AppsV1().Deployments(namespace).Create(context.TODO(),
+ &appsv1.Deployment{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: serverName,
+ },
+ Spec: appsv1.DeploymentSpec{
+ Selector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "run": serverName,
+ },
+ },
+ Replicas: &serverReplicas,
+ Template: corev1.PodTemplateSpec{
+ ObjectMeta: metav1.ObjectMeta{
+ Labels: map[string]string{
+ "run": serverName,
+ },
+ },
+ Spec: corev1.PodSpec{
+ ServiceAccountName: serverName,
+ Containers: []corev1.Container{
+ {
+ Name: serverName,
+ Image: serverImage,
+ Env: []corev1.EnvVar{
+ {
+ Name: "SUBMARINE_SERVER_PORT",
+ Value: "8080",
+ },
+ {
+ Name: "SUBMARINE_SERVER_PORT_8080_TCP",
+ Value: "8080",
+ },
+ {
+ Name: "SUBMARINE_SERVER_DNS_NAME",
+ Value: serverName + "." + namespace,
+ },
+ {
+ Name: "K8S_APISERVER_URL",
+ Value: "kubernetes.default.svc",
+ },
+ },
+ Ports: []corev1.ContainerPort{
+ {
+ ContainerPort: 8080,
+ },
+ },
+ ImagePullPolicy: "IfNotPresent",
+ },
+ },
+ },
+ },
+ },
+ },
+ metav1.CreateOptions{})
+ klog.Info(" Create Deployment: ", deployment.Name)
+ }
+
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if deployment_err != nil {
+ return deployment_err
+ }
+
+ // TODO: (sample-controller) controller.go:287 ~ 293
+
+ return nil
+}
+
// syncHandler compares the actual state with the desired, and attempts to
// converge the two. It then updates the Status block of the Foo resource
// with the current status of the resource.
@@ -223,6 +351,18 @@ func (c *Controller) syncHandler(key string) error {
b, err := json.MarshalIndent(submarine.Spec, "", " ")
fmt.Println(string(b))
+ // Create submarine-server
+ serverImage := submarine.Spec.Server.Image
+ serverReplicas := *submarine.Spec.Server.Replicas
+ if serverImage == "" {
+ serverImage = "apache/submarine:server-" + submarine.Spec.Version
+ }
+ err = c.newSubmarineServer(serverImage, serverReplicas, namespace)
+
+ if err != nil {
+ return err
+ }
+
return nil
}
diff --git a/submarine-cloud-v2/main.go b/submarine-cloud-v2/main.go
index 1d94803..8356dee 100644
--- a/submarine-cloud-v2/main.go
+++ b/submarine-cloud-v2/main.go
@@ -19,16 +19,16 @@ package main
import (
"flag"
- "time"
kubeinformers "k8s.io/client-go/informers"
- "k8s.io/klog/v2"
- "k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ "k8s.io/klog/v2"
"os"
- "submarine-cloud-v2/pkg/signals"
clientset "submarine-cloud-v2/pkg/generated/clientset/versioned"
informers "submarine-cloud-v2/pkg/generated/informers/externalversions"
+ "submarine-cloud-v2/pkg/signals"
+ "time"
)
var (
@@ -52,7 +52,7 @@ func main() {
stopCh := signals.SetupSignalHandler()
cfg, err := initKubeConfig()
-
+
if err != nil {
klog.Fatalf("Error building kubeconfig: %s", err.Error())
}
@@ -69,13 +69,15 @@ func main() {
kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, time.Second*30)
submarineInformerFactory := informers.NewSharedInformerFactory(submarineClient, time.Second*30)
-
+
// TODO: Pass informers to NewController()
// ex: namespace informer
// Create a Submarine operator
controller := NewController(kubeClient, submarineClient,
kubeInformerFactory.Apps().V1().Deployments(),
+ kubeInformerFactory.Core().V1().Services(),
+ kubeInformerFactory.Core().V1().ServiceAccounts(),
submarineInformerFactory.Submarine().V1alpha1().Submarines())
// notice that there is no need to run Start methods in a separate goroutine. (i.e. go kubeInformerFactory.Start(stopCh)
@@ -91,6 +93,6 @@ func main() {
func init() {
flag.BoolVar(&incluster, "incluster", false, "Run submarine-operator in-cluster")
- flag.StringVar(&kubeconfig, "kubeconfig", os.Getenv("HOME") + "/.kube/config", "Path to a kubeconfig. Only required if out-of-cluster.")
+ flag.StringVar(&kubeconfig, "kubeconfig", os.Getenv("HOME")+"/.kube/config", "Path to a kubeconfig. Only required if out-of-cluster.")
flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org