github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/cmd/server/server.go (about)

     1  // Package server is the micro server which runs the whole system
     2  package server
     3  
     4  import (
     5  	"os"
     6  	"os/signal"
     7  	"strings"
     8  	"syscall"
     9  	"time"
    10  
    11  	"github.com/tickoalcantara12/micro/v3/cmd"
    12  	"github.com/tickoalcantara12/micro/v3/service/auth"
    13  	log "github.com/tickoalcantara12/micro/v3/service/logger"
    14  	"github.com/tickoalcantara12/micro/v3/service/runtime"
    15  	"github.com/urfave/cli/v2"
    16  )
    17  
    18  var (
    19  	// list of services managed
    20  	services = []string{
    21  		"registry", // :8000
    22  		"broker",   // :8003
    23  		"network",  // :8443
    24  		"runtime",  // :8088
    25  		"config",   // :8001
    26  		"store",    // :8002
    27  		"events",   // :unset
    28  		"auth",     // :8010
    29  		"proxy",    // :8081
    30  		"api",      // :8080
    31  	}
    32  )
    33  
    34  var (
    35  	// Name of the server microservice
    36  	Name = "server"
    37  	// Address is the server address
    38  	Address = ":10001"
    39  )
    40  
    41  func init() {
    42  	command := &cli.Command{
    43  		Name:  "server",
    44  		Usage: "Run the micro server",
    45  		Description: `Launching the micro server ('micro server') will enable one to connect to it by
    46  		setting the appropriate Micro environment (see 'micro env' && 'micro env --help') commands.`,
    47  		Flags: []cli.Flag{
    48  			&cli.StringFlag{
    49  				Name:    "address",
    50  				Usage:   "Set the micro server address :10001",
    51  				EnvVars: []string{"MICRO_SERVER_ADDRESS"},
    52  			},
    53  			&cli.StringFlag{
    54  				Name:    "image",
    55  				Usage:   "Set the micro server image",
    56  				EnvVars: []string{"MICRO_SERVER_IMAGE"},
    57  				Value:   "micro/micro:latest",
    58  			},
    59  		},
    60  		Action: func(ctx *cli.Context) error {
    61  			Run(ctx)
    62  			return nil
    63  		},
    64  	}
    65  
    66  	for _, p := range Plugins() {
    67  		if cmds := p.Commands(); len(cmds) > 0 {
    68  			command.Subcommands = append(command.Subcommands, cmds...)
    69  		}
    70  
    71  		if flags := p.Flags(); len(flags) > 0 {
    72  			command.Flags = append(command.Flags, flags...)
    73  		}
    74  	}
    75  
    76  	cmd.Register(command)
    77  }
    78  
    79  // Run runs the entire platform
    80  func Run(context *cli.Context) error {
    81  	if context.Args().Len() > 0 {
    82  		cli.ShowSubcommandHelp(context)
    83  		os.Exit(1)
    84  	}
    85  
    86  	// TODO: reimplement peering of servers e.g --peer=node1,node2,node3
    87  	// peers are configured as network nodes to cluster between
    88  	log.Info("Starting server")
    89  
    90  	// parse the env vars
    91  	var envvars []string
    92  	for _, val := range os.Environ() {
    93  		comps := strings.Split(val, "=")
    94  		if len(comps) != 2 {
    95  			continue
    96  		}
    97  
    98  		// only process MICRO_ values
    99  		if !strings.HasPrefix(comps[0], "MICRO_") {
   100  			continue
   101  		}
   102  
   103  		// skip the profile and proxy, that's set below since it can be service specific
   104  		if comps[0] == "MICRO_PROFILE" || comps[0] == "MICRO_PROXY" {
   105  			continue
   106  		}
   107  
   108  		envvars = append(envvars, val)
   109  	}
   110  
   111  	// save the runtime
   112  	runtimeServer := runtime.DefaultRuntime
   113  	// get the runtime environment
   114  	runtimeEnv := runtimeServer.String()
   115  	// exit after starting
   116  	runtimeExit := false
   117  
   118  	// start the services
   119  	for _, service := range services {
   120  		log.Infof("Registering %s", service)
   121  
   122  		// all things run by the server are `micro service [name]`
   123  		cmdArgs := []string{"service"}
   124  
   125  		// TODO: remove hacks
   126  		profile := context.String("profile")
   127  
   128  		env := envvars
   129  		env = append(env, "MICRO_PROFILE="+profile)
   130  
   131  		// set the proxy address, default to the network running locally
   132  		if service != "network" {
   133  			proxy := context.String("proxy_address")
   134  			if len(proxy) == 0 {
   135  				proxy = "127.0.0.1:8443"
   136  			}
   137  			env = append(env, "MICRO_PROXY="+proxy)
   138  		}
   139  
   140  		// for kubernetes we want to provide a port and instruct the service to bind to it. we don't do
   141  		// this locally because the services are not isolated and the ports will conflict
   142  		var port string
   143  
   144  		if runtimeEnv == "kubernetes" {
   145  			switch service {
   146  			case "api":
   147  				// run the api on :443, the standard port for HTTPs
   148  				port = "443"
   149  				env = append(env, "MICRO_API_ADDRESS=:443")
   150  				// pass :8080 for the internal service address, since this is the default port used for the
   151  				// static (k8s) router. Because the http api will register on :443 it won't conflict
   152  				env = append(env, "MICRO_SERVICE_ADDRESS=:8080")
   153  			case "proxy":
   154  				// run the proxy on :443, the standard port for HTTPs
   155  				port = "443"
   156  				env = append(env, "MICRO_PROXY_ADDRESS=:443")
   157  				// pass :8080 for the internal service address, since this is the default port used for the
   158  				// static (k8s) router. Because the grpc proxy will register on :443 it won't conflict
   159  				env = append(env, "MICRO_SERVICE_ADDRESS=:8080")
   160  			case "network":
   161  				port = "8443"
   162  				env = append(env, "MICRO_SERVICE_ADDRESS=:8443")
   163  			default:
   164  				port = "8080"
   165  				env = append(env, "MICRO_SERVICE_ADDRESS=:8080")
   166  			}
   167  
   168  			// exit after starting services
   169  			runtimeExit = true
   170  		}
   171  
   172  		// we want to pass through the global args so go up one level in the context lineage
   173  		if len(context.Lineage()) > 1 {
   174  			globCtx := context.Lineage()[1]
   175  			for _, f := range globCtx.FlagNames() {
   176  				cmdArgs = append(cmdArgs, "--"+f, context.String(f))
   177  			}
   178  		}
   179  		cmdArgs = append(cmdArgs, service)
   180  
   181  		// runtime based on environment we run the service in
   182  		args := []runtime.CreateOption{
   183  			runtime.WithCommand(os.Args[0]),
   184  			runtime.WithArgs(cmdArgs...),
   185  			runtime.WithEnv(env),
   186  			runtime.WithPort(port),
   187  			runtime.WithRetries(10),
   188  			runtime.WithServiceAccount("micro"),
   189  			runtime.WithVolume("store-pvc", "/store"),
   190  			runtime.CreateImage(context.String("image")),
   191  			runtime.CreateNamespace("micro"),
   192  			runtime.WithSecret("MICRO_AUTH_PUBLIC_KEY", auth.DefaultAuth.Options().PublicKey),
   193  			runtime.WithSecret("MICRO_AUTH_PRIVATE_KEY", auth.DefaultAuth.Options().PrivateKey),
   194  		}
   195  
   196  		// NOTE: we use Version right now to check for the latest release
   197  		muService := &runtime.Service{Name: service, Version: "latest"}
   198  		if err := runtimeServer.Create(muService, args...); err != nil {
   199  			log.Errorf("Failed to create runtime environment: %v", err)
   200  			return err
   201  		}
   202  	}
   203  
   204  	// server is deployed as a job in k8s, meaning it should exit once the services have been created.
   205  	if runtimeExit {
   206  		return nil
   207  	}
   208  
   209  	log.Info("Starting server runtime")
   210  
   211  	// start the runtime
   212  	if err := runtimeServer.Start(); err != nil {
   213  		log.Fatal(err)
   214  		return err
   215  	}
   216  
   217  	ch := make(chan os.Signal, 1)
   218  	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL)
   219  	<-ch
   220  
   221  	runtimeServer.Stop()
   222  	log.Info("Stopped server")
   223  
   224  	// just wait 1 sec
   225  	<-time.After(time.Second)
   226  
   227  	return nil
   228  }