mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
updated oam-k8s-runtime and go through rollout fix bugs
Signed-off-by: 天元 <jianbo.sjb@alibaba-inc.com>
This commit is contained in:
4
Makefile
4
Makefile
@@ -126,10 +126,12 @@ core-run: generate fmt vet manifests
|
||||
|
||||
# Install CRDs and Definitions of Vela Core into a cluster, this is for develop convenient.
|
||||
core-install: manifests
|
||||
kubectl apply -f hack/namespace.yaml
|
||||
kubectl apply -f charts/vela-core/crds/
|
||||
kubectl apply -f charts/vela-core/templates/defwithtemplate/
|
||||
kubectl apply -f charts/vela-core/templates/definitions/
|
||||
bin/vela system update
|
||||
kubectl apply -f charts/vela-core/templates/velaConfig.yaml
|
||||
bin/vela workloads
|
||||
|
||||
# Uninstall CRDs and Definitions of Vela Core from a cluster, this is for develop convenient.
|
||||
core-uninstall: manifests
|
||||
|
||||
@@ -2,7 +2,8 @@ apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: vela-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
# TODO: Currently namespace MUST be vela-system
|
||||
namespace: vela-system
|
||||
data:
|
||||
servicemonitors.monitoring.coreos.com: |
|
||||
{
|
||||
|
||||
@@ -9,8 +9,8 @@ name: testapp
|
||||
services:
|
||||
express-server:
|
||||
type: webservice
|
||||
image: oamdev/testapp:v1
|
||||
port: 8080
|
||||
image: oamdev/testapp:rolling01
|
||||
port: 80
|
||||
|
||||
rollout:
|
||||
replica: 5
|
||||
@@ -18,7 +18,16 @@ services:
|
||||
interval: "30s"
|
||||
|
||||
route:
|
||||
domain: example.com
|
||||
domain: "example.com"
|
||||
```
|
||||
|
||||
If your cluster don't have ingress, you could set domain to be empty like below:
|
||||
|
||||
```yaml
|
||||
...
|
||||
route:
|
||||
- domain: "example.com"
|
||||
+ domain: ""
|
||||
```
|
||||
|
||||
> The full specification of `rollout` could be found [here](references/traits/rollout.md)
|
||||
@@ -60,9 +69,22 @@ Visiting this app by:
|
||||
|
||||
```bash
|
||||
$ curl -H "Host:example.com" http://<your-ingress-IP-address>/
|
||||
Hello World%
|
||||
Hello World -- Rolling 01
|
||||
```
|
||||
|
||||
If you don't have ingress in your cluster and you leave domain to be empty, then you could visit this app by:
|
||||
|
||||
```bash
|
||||
$ vela port-forward testapp --route
|
||||
Forwarding from 127.0.0.1:8080 -> 80
|
||||
Forwarding from [::1]:8080 -> 80
|
||||
|
||||
Forward successfully! Opening browser ...
|
||||
Handling connection for 8080
|
||||
```
|
||||
|
||||
It will automatically open browser for you.
|
||||
|
||||
In day 2, assuming we have make some changes on our app and build the new image and name it by `oamdev/testapp:v2`.
|
||||
|
||||
Let's update the appfile by:
|
||||
@@ -72,9 +94,9 @@ name: testapp
|
||||
services:
|
||||
express-server:
|
||||
type: webservice
|
||||
- image: oamdev/testapp:v1
|
||||
+ image: oamdev/testapp:v2
|
||||
port: 8080
|
||||
- image: oamdev/testapp:rolling01
|
||||
+ image: oamdev/testapp:rolling02
|
||||
port: 80
|
||||
rollout:
|
||||
replica: 5
|
||||
stepWeight: 20
|
||||
@@ -89,22 +111,51 @@ Apply this `appfile.yaml` again:
|
||||
$ vela up
|
||||
```
|
||||
|
||||
You could then try to `curl` your app multiple times and and see how the new instances being promoted following Canary rollout strategy:
|
||||
|
||||
You could run `vela status` several times to see the instance rolling:
|
||||
|
||||
```shell script
|
||||
$ vela status testapp
|
||||
About:
|
||||
|
||||
Name: testapp
|
||||
Namespace: myenv
|
||||
Created at: 2020-11-12 19:02:40.353693 +0800 CST
|
||||
Updated at: 2020-11-12 19:02:40.353693 +0800 CST
|
||||
|
||||
Services:
|
||||
|
||||
- Name: express-server
|
||||
Type: webservice
|
||||
HEALTHY express-server-v2:Ready: 1/1 express-server-v1:Ready: 4/4
|
||||
Traits:
|
||||
- ✅ rollout: interval=30s
|
||||
replica=5
|
||||
stepWeight=20
|
||||
- ✅ route: Visiting by using 'vela port-forward testapp --route'
|
||||
|
||||
Last Deployment:
|
||||
Created at: 2020-11-12 17:20:46 +0800 CST
|
||||
Updated at: 2020-11-12T19:02:40+08:00
|
||||
```
|
||||
|
||||
You could then try to `curl` your app multiple times and and see how the new instances being promoted following Canary
|
||||
rollout strategy: (Note: Using `vela port-forward` will not see this as port-forward will proxy network on fixed port, only ingress
|
||||
has loadbalance.)
|
||||
|
||||
```bash
|
||||
$ curl -H "Host:example.com" http://<your-ingress-ip-address>/
|
||||
Hello World -- Updated Version Two!%
|
||||
Hello World -- This is rolling 02
|
||||
$ curl -H "Host:example.com" http://<your-ingress-ip-address>/
|
||||
Hello World%
|
||||
Hello World -- Rolling 01
|
||||
$ curl -H "Host:example.com" http://<your-ingress-ip-address>/
|
||||
Hello World%
|
||||
Hello World -- Rolling 01
|
||||
$ curl -H "Host:example.com" http://<your-ingress-ip-address>/
|
||||
Hello World -- Updated Version Two!%
|
||||
Hello World -- This is rolling 02
|
||||
$ curl -H "Host:example.com" http://<your-ingress-ip-address>/
|
||||
Hello World%
|
||||
Hello World -- Rolling 01
|
||||
$ curl -H "Host:example.com" http://<your-ingress-ip-address>/
|
||||
Hello World -- Updated Version Two!%
|
||||
Hello World -- This is rolling 02
|
||||
```
|
||||
|
||||
For every 30 second, 20% more traffic will be shifted to the new instance from the old instance as we configured in Appfile.
|
||||
|
||||
|
||||
2
go.mod
2
go.mod
@@ -9,7 +9,7 @@ require (
|
||||
github.com/briandowns/spinner v1.11.1
|
||||
github.com/coreos/prometheus-operator v0.41.1
|
||||
github.com/crossplane/crossplane-runtime v0.10.0
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.3.2
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.3.3-0.20201112082656-22b7738dcdf3
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/gertd/go-pluralize v0.1.7
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -414,8 +414,8 @@ github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crossplane/crossplane-runtime v0.10.0 h1:H8YvMcrm1uzZYpwU/BpxjRQfceVulxgYJMx4rmX38Hg=
|
||||
github.com/crossplane/crossplane-runtime v0.10.0/go.mod h1:cJl5ZZONisre4v6wTmbrC8Jh3AI+erq/lNaxZzv9tnU=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.3.2 h1:iUBsYYn+33X1liRm6sn7oUA2hoXCWW8ik5QtATLZNxk=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.3.2/go.mod h1:K4/F1XOPBvmW/PaRSPL3wNA4kCrFGUQC7WkBYcwIGx8=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.3.3-0.20201112082656-22b7738dcdf3 h1:0AMLxvQoU14r3qTvGZ8olSwvBq7McL1ZGdiHAQ7L8M8=
|
||||
github.com/crossplane/oam-kubernetes-runtime v0.3.3-0.20201112082656-22b7738dcdf3/go.mod h1:K4/F1XOPBvmW/PaRSPL3wNA4kCrFGUQC7WkBYcwIGx8=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4=
|
||||
|
||||
4
hack/namespace.yaml
Normal file
4
hack/namespace.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: vela-system
|
||||
@@ -1,6 +1,7 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
|
||||
"github.com/crossplane/oam-kubernetes-runtime/pkg/oam"
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -234,3 +237,11 @@ func getApplicationDir(envName string) (string, error) {
|
||||
_, err := system.CreateIfNotExist(appDir)
|
||||
return appDir, err
|
||||
}
|
||||
|
||||
func GetAppConfig(ctx context.Context, c client.Client, app *Application, env *types.EnvMeta) (*v1alpha2.ApplicationConfiguration, error) {
|
||||
appConfig := &v1alpha2.ApplicationConfiguration{}
|
||||
if err := c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, appConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appConfig, nil
|
||||
}
|
||||
|
||||
@@ -9,6 +9,13 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
types2 "k8s.io/apimachinery/pkg/types"
|
||||
|
||||
"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/crossplane/oam-kubernetes-runtime/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/api/types"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -39,6 +46,8 @@ type VelaPortForwardOptions struct {
|
||||
f k8scmdutil.Factory
|
||||
kcPortForwardOptions *cmdpf.PortForwardOptions
|
||||
ClientSet kubernetes.Interface
|
||||
Client client.Client
|
||||
routeTrait bool
|
||||
}
|
||||
|
||||
func NewPortForwardCommand(c types.Args, ioStreams velacmdutil.IOStreams) *cobra.Command {
|
||||
@@ -49,6 +58,7 @@ func NewPortForwardCommand(c types.Args, ioStreams velacmdutil.IOStreams) *cobra
|
||||
PortForwarder: &defaultPortForwarder{ioStreams},
|
||||
},
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "port-forward APP_NAME [options] [LOCAL_PORT:]REMOTE_PORT [...[LOCAL_PORT_N:]REMOTE_PORT_N]",
|
||||
Short: "Forward one or more local ports to a Pod of a service in an application",
|
||||
@@ -58,6 +68,11 @@ func NewPortForwardCommand(c types.Args, ioStreams velacmdutil.IOStreams) *cobra
|
||||
ioStreams.Error("Please specify application name.")
|
||||
return nil
|
||||
}
|
||||
newClient, err := client.New(o.VelaC.Config, client.Options{Scheme: o.VelaC.Schema})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Client = newClient
|
||||
if err := o.Init(context.Background(), cmd, args); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -77,6 +92,7 @@ func NewPortForwardCommand(c types.Args, ioStreams velacmdutil.IOStreams) *cobra
|
||||
cmd.Flags().Duration(podRunningTimeoutFlag, defaultPodExecTimeout,
|
||||
"The length of time (like 5s, 2m, or 3h, higher than zero) to wait until at least one pod is running",
|
||||
)
|
||||
cmd.Flags().BoolVar(&o.routeTrait, "route", false, "forward ports from route trait service")
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -111,11 +127,56 @@ func (o *VelaPortForwardOptions) Init(ctx context.Context, cmd *cobra.Command, a
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetRouteServiceName(appconfig *v1alpha2.ApplicationConfiguration, svcName string) string {
|
||||
for _, comp := range appconfig.Status.Workloads {
|
||||
if comp.ComponentName != svcName {
|
||||
continue
|
||||
}
|
||||
for _, tr := range comp.Traits {
|
||||
// TODO check from Capability
|
||||
if tr.Reference.Kind == "Route" && tr.Reference.APIVersion == "standard.oam.dev/v1alpha1" {
|
||||
return tr.Reference.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (o *VelaPortForwardOptions) Complete() error {
|
||||
svcName, err := util.AskToChooseOneService(o.App.GetComponents())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if o.routeTrait {
|
||||
appconfig, err := application.GetAppConfig(o.Context, o.Client, o.App, o.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
routeSvc := GetRouteServiceName(appconfig, svcName)
|
||||
if routeSvc == "" {
|
||||
return fmt.Errorf("no route trait found in %s %s", o.App.Name, svcName)
|
||||
}
|
||||
var svc = corev1.Service{}
|
||||
err = o.Client.Get(o.Context, types2.NamespacedName{Name: routeSvc, Namespace: o.Env.Namespace}, &svc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(svc.Spec.Ports) <= 0 {
|
||||
return fmt.Errorf("no port found in service %s", routeSvc)
|
||||
}
|
||||
val := strconv.Itoa(int(svc.Spec.Ports[0].Port))
|
||||
if val == "80" {
|
||||
val = "8080:80"
|
||||
} else if val == "443" {
|
||||
val = "8443:443"
|
||||
}
|
||||
o.Args = append(o.Args, val)
|
||||
args := make([]string, len(o.Args))
|
||||
copy(args, o.Args)
|
||||
args[0] = "svc/" + routeSvc
|
||||
return o.kcPortForwardOptions.Complete(o.f, o.Cmd, args)
|
||||
}
|
||||
|
||||
podName, err := o.getPodName(svcName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -44,6 +44,7 @@ func TestPortForwardCommand(t *testing.T) {
|
||||
kcPortForwardOptions: &portforward.PortForwardOptions{},
|
||||
f: tf,
|
||||
ClientSet: fakeClientSet,
|
||||
VelaC: fakeC,
|
||||
}
|
||||
err := o.Init(context.Background(), cmd, []string{"fakeApp", "8081:8080"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -403,8 +403,8 @@ func getApp(ctx context.Context, c client.Client, compName, appName string, env
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
appConfig := &v1alpha2.ApplicationConfiguration{}
|
||||
if err = c.Get(ctx, client.ObjectKey{Namespace: env.Namespace, Name: app.Name}, appConfig); err != nil {
|
||||
appConfig, err := application.GetAppConfig(ctx, c, app, env)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return app, appConfig, nil
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
@@ -55,12 +57,12 @@ func init() {
|
||||
// Note: reconsider delegating the work to helm operator.
|
||||
func Install(kubecli client.Client) {
|
||||
velaConfig, err := fetchVelaConfig(kubecli)
|
||||
if err != nil {
|
||||
log.Error(err, "fetchVelaConfig failed")
|
||||
if apierrors.IsNotFound(err) {
|
||||
log.Info("no ConfigMap('vela-config') found in vela-system namespace, will not install any dependency")
|
||||
return
|
||||
}
|
||||
if velaConfig == nil {
|
||||
log.Info("no vela config")
|
||||
if err != nil {
|
||||
log.Error(err, "fetch ConfigMap('vela-config') in vela-system namespace failed")
|
||||
return
|
||||
}
|
||||
for key, chart := range velaConfig.Data {
|
||||
@@ -96,7 +98,7 @@ func fetchVelaConfig(kubecli client.Client) (*v1.ConfigMap, error) {
|
||||
velaConfigNN := k8stypes.NamespacedName{Name: VelaConfigName, Namespace: types.DefaultOAMNS}
|
||||
velaConfig := &v1.ConfigMap{}
|
||||
if err := kubecli.Get(context.TODO(), velaConfigNN, velaConfig); err != nil {
|
||||
return nil, client.IgnoreNotFound(err)
|
||||
return nil, err
|
||||
}
|
||||
return velaConfig, nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
standardv1alpha1 "github.com/oam-dev/kubevela/api/v1alpha1"
|
||||
|
||||
@@ -100,6 +101,10 @@ func (n *Nginx) CheckStatus(routeTrait *standardv1alpha1.Route) (string, []runti
|
||||
|
||||
func (*Nginx) Construct(routeTrait *standardv1alpha1.Route) []*v1beta1.Ingress {
|
||||
|
||||
// Don't create ingress if no host set, this is used for local K8s cluster demo and the route trait will create K8s service only.
|
||||
if routeTrait.Spec.Host == "" || strings.Contains(routeTrait.Spec.Host, "localhost") || strings.Contains(routeTrait.Spec.Host, "127.0.0.1") {
|
||||
return nil
|
||||
}
|
||||
var ingresses []*v1beta1.Ingress
|
||||
for idx, rule := range routeTrait.Spec.Rules {
|
||||
name := rule.Name
|
||||
|
||||
@@ -125,7 +125,7 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
||||
oamutil.PatchCondition(ctx, r, &routeTrait,
|
||||
cpv1alpha1.ReconcileError(errors.Wrap(err, errApplyNginxIngress)))
|
||||
}
|
||||
r.record.Event(eventObj, event.Normal("nginx ingress created",
|
||||
r.record.Event(eventObj, event.Normal("nginx ingress patched",
|
||||
fmt.Sprintf("successfully server side patched a route trait `%s`", routeTrait.Name)))
|
||||
}
|
||||
// TODO(wonderflow): GC mechanism for no used ingress, service, issuer
|
||||
|
||||
@@ -132,6 +132,9 @@ func (d *RouteChecker) Check(ctx context.Context, reference runtimev1alpha1.Type
|
||||
}
|
||||
message += fmt.Sprintf("\tVisiting URL: %s\tIP: %s\n", url, addr)
|
||||
}
|
||||
if len(route.Status.Ingresses) == 0 {
|
||||
message += fmt.Sprintf("Visiting by using 'vela port-forward %s --route'\n", appConfig.Name)
|
||||
}
|
||||
return StatusDone, message, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ func GetWorkloadsFromCluster(ctx context.Context, namespace string, c types.Args
|
||||
}
|
||||
gvk, err := util.GetGVKFromDefinition(dm, wd.Spec.Reference)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("make sure you have installed CRD(controller) for this capability '%s': %v ", wd.Name, err)
|
||||
}
|
||||
tmp.CrdInfo = &types.CrdInfo{
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
@@ -99,7 +99,7 @@ func GetTraitsFromCluster(ctx context.Context, namespace string, c types.Args, s
|
||||
}
|
||||
gvk, err := util.GetGVKFromDefinition(dm, td.Spec.Reference)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("make sure you have installed CRD(controller) for this capability '%s': %v ", td.Name, err)
|
||||
}
|
||||
tmp.CrdInfo = &types.CrdInfo{
|
||||
APIVersion: gvk.GroupVersion().String(),
|
||||
|
||||
Reference in New Issue
Block a user