github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/docs/reference/README.md (about)

     1  ---
     2  title: Reference
     3  keywords: micro
     4  tags: [micro]
     5  sidebar: home_sidebar
     6  permalink: /reference
     7  summary: Reference - a comprehensive guide to Micro
     8  ---
     9  
    10  ## Reference
    11  {: .no_toc }
    12  
    13  This reference doc is an in depth guide for the technical details and usage of Micro
    14  
    15  ## Contents
    16  {: .no_toc }
    17  
    18  * TOC
    19  {:toc}
    20  
    21  ## Overview
    22  
    23  Micro is a platform for cloud native development. It consists of a server, command line interface and 
    24  service framework which enables you to build, run, manage and consume Micro services. This reference 
    25  walks through the majority of Micro in depth and attempts to help guide you through any usage. It 
    26  should be thought of much like a language spec and will evolve over time.
    27  
    28  ## Installation
    29  
    30  Below are the instructions for installing micro locally, in docker or on kubernetes
    31  
    32  ### Local 
    33  
    34  Micro can be installed locally in the following way. We assume for the most part a Linux env with Go and Git installed.
    35  
    36  #### Go Get
    37  
    38  ```
    39  go get github.com/tickoalcantara12/micro/v3
    40  ```
    41  
    42  #### Docker
    43  
    44  ```sh
    45  docker pull ghcr.io/micro/micro:latest
    46  ```
    47  
    48  #### Release Binaries
    49  
    50  ```sh
    51  # MacOS
    52  curl -fsSL https://raw.githubusercontent.com/micro/micro/master/scripts/install.sh | /bin/bash
    53  
    54  # Linux
    55  wget -q  https://raw.githubusercontent.com/micro/micro/master/scripts/install.sh -O - | /bin/bash
    56  
    57  # Windows
    58  powershell -Command "iwr -useb https://raw.githubusercontent.com/micro/micro/master/scripts/install.ps1 | iex"
    59  ```
    60  
    61  ### Kubernetes
    62  
    63  Micro can be installed onto a Kubernetes cluster using helm. Micro will be deployed in full and leverage zero-dep implementations designed for Kubernetes. For example, micro store will internally leverage a file store on a persistent volume, meaning there are no infrastructure dependencies required.
    64  
    65  #### Dependencies
    66  
    67  You will need to be connected to a Kubernetes cluster
    68  
    69  #### Install
    70  
    71  Install micro with the following commands:
    72  
    73  ```shell
    74  helm repo add micro https://micro.github.io/helm
    75  helm install micro micro/micro
    76  ```
    77  
    78  #### Uninstall
    79  
    80  Uninstall micro with the following commands:
    81  
    82  ```shell
    83  helm uninstall micro
    84  helm repo remove micro
    85  ```
    86  
    87  ## Server
    88  
    89  The micro server is a distributed systems runtime for the Cloud and beyond. It provides the building 
    90  blocks for distributed systems development as a set of services, command line and service framework. 
    91  The server is much like a distributed operating system in the sense that each component runs 
    92  independent of each other but work together as one system. This composition allows us to use a 
    93  microservices architecture pattern even for the platform.
    94  
    95  ### Features
    96  
    97  The server provides the below functionality as built in primitives for services development.
    98  
    99  - Authentication
   100  - Configuration
   101  - PubSub Messaging
   102  - Event Streaming
   103  - Service Discovery
   104  - Service Networking
   105  - Key-Value Storage
   106  - HTTP API Gateway
   107  - gRPC Identity Proxy
   108  - Web Dashboard
   109  
   110  ### Usage
   111  
   112  To start the server simply run
   113  
   114  ```sh
   115  micro server
   116  ```
   117  
   118  In docker
   119  
   120  ```
   121  sudo docker run -p 8080:8080 -p 8081:8081 ghcr.io/micro/micro:latest server
   122  ```
   123  
   124  This will boot the entire system and services including a http api on :8080 and grpc proxy on :8081
   125  
   126  ### Help
   127  
   128  Run the following command to check help output
   129  ```
   130  micro --help
   131  ```
   132  
   133  ### Environment
   134  
   135  Environments define where the server is running, by default this should be local
   136  
   137  Check with the following command
   138  
   139  ```
   140  micro env
   141  ```
   142  
   143  To set the environment do
   144  
   145  ```
   146  micro env set local
   147  ```
   148  
   149  ### Login
   150  
   151  Before starting login using the default user `admin` with password `micro`
   152  
   153  ```
   154  micro login
   155  ```
   156  
   157  ### Commands
   158  
   159  Here's a quick list of useful commands
   160  
   161  ```
   162  micro --help	# execute help to list commands
   163  micro env	# show the environment config
   164  micro login	# login to the server
   165  micro services	# check what's running
   166  micro status	# check service status
   167  ```
   168  
   169  ## Start helloworld
   170  
   171  Run helloworld and check its status
   172  
   173  ```
   174  # check env is set to local
   175  micro env
   176  # run the helloworld service
   177  micro run github.com/micro/services/helloworld
   178  # check the service status to see it's running
   179  micro status
   180  # once running should be listed in services
   181  micro services
   182  ```
   183  
   184  Call the service and verify output
   185  
   186  ```sh
   187  $ micro helloworld --name=Alice
   188  {
   189          "msg": "Hello Alice"
   190  }
   191  ```
   192  
   193  Curl it from the API
   194  
   195  ```
   196  curl "http://localhost:8080/helloworld/Call?name=Alice"
   197  ```
   198  
   199  Stop the service
   200  
   201  ```
   202  micro kill helloworld
   203  ```
   204  
   205  ## Command Line
   206  
   207  The command line interface is the primary way to interact with a micro server. It's a simple binary that 
   208  can either be interacted with using simple commands or an interactive prompt. The CLI proxies all commands 
   209  as RPC calls to the Micro server. In many of the builtin commands it will perform formatting and additional 
   210  syntactic work.
   211  
   212  ### Builtin Commands
   213  
   214  Built in commands are system or configuration level commands for interacting with the server or 
   215  changing user config. For the most part this is syntactic sugar for user convenience. Here's a 
   216  subset of well known commands.
   217  
   218  ```
   219  signup
   220  login
   221  run
   222  update
   223  kill
   224  services
   225  logs
   226  status
   227  env
   228  user
   229  ```
   230  
   231  The micro binary and each subcommand has a --help flag to provide a usage guide. The majority should be 
   232  obvious to the user. We will go through a few in more detail.
   233  
   234  <!--
   235  
   236  #### Signup
   237  
   238  Signup is a command which attempts to query a "signup" to register a new account, this is env specific and requires a signup service to be 
   239  running. By default locally this will not exist and we expect the user to use the admin/micro credentials to administer the system. 
   240  You can then choose to run your own signup service conforming to the proto in micro/proto or use `micro auth create account`. 
   241  
   242  Signup is seen as a command for those who want to run their own micro server for others and potentially license the software to take payment.
   243  --->
   244  
   245  #### Login
   246  
   247  Login authenticates the user and stores credentials locally in a .micro/tokens file. This calls the micro auth service to authenticate the 
   248  user against existing accounts stored in the system. Login asks for a username and password at the prompt.
   249  
   250  ### Dynamic Commands
   251  
   252  When issuing a command to the Micro CLI (ie. `micro command`), if the command is not a builtin, Micro will try to dynamically resolve this command and call
   253  a service running. Let's take the `micro registry` command, because although the registry is a core service that's running by default on a local Micro setup,
   254  the `registry` command is not a builtin one.
   255  
   256  With the `--help` flag, we can get information about available subcommands and flags
   257  
   258  ```sh
   259  $ micro registry --help
   260  NAME:
   261  	micro registry
   262  
   263  VERSION:
   264  	latest
   265  
   266  USAGE:
   267  	micro registry [command]
   268  
   269  COMMANDS:
   270  	deregister
   271  	getService
   272  	listServices
   273  	register
   274  	watch
   275  ```
   276  
   277  The commands listed are endpoints of the `registry` service (see `micro services`).
   278  
   279  To see the flags (which are essentially endpoint request parameters) for a subcommand:
   280  
   281  ```sh
   282  $ micro registry getService --help
   283  NAME:
   284  	micro registry getService
   285  
   286  USAGE:
   287  	micro registry getService [flags]
   288  
   289  FLAGS:
   290  	--service string
   291  	--options_ttl int64
   292  	--options_domain string
   293  
   294  ```
   295  
   296  At this point it is useful to have a look at the proto of the [registry service here](https://github.com/tickoalcantara12/micro/blob/master/proto/registry/registry.proto).
   297  
   298  In particular, let's see the `GetService` endpoint definition to understand how request parameters map to flags:
   299  
   300  ```proto
   301  message Options {
   302  	int64 ttl = 1;
   303  	string domain = 2;
   304  }
   305  
   306  message GetRequest {
   307  	string service = 1;
   308  	Options options = 2;
   309  }
   310  ```
   311  
   312  As the above definition tells us, the request of `GetService` has the field `service` at the top level, and fields `ttl` and `domain` in an options structure.
   313  The dynamic CLI maps the underscored flagnames (ie. `options_domain`) to request fields, so the following request JSON:
   314  
   315  ```js
   316  {
   317      "service": "serviceName",
   318      "options": {
   319          "domain": "domainExample"
   320      }
   321  }
   322  ```
   323  
   324  is equivalent to the following flags:
   325  
   326  ```sh
   327  micro registry getService --service=serviceName --options_domain=domainExample
   328  ```
   329  
   330  ### User Config
   331  
   332  The command line uses local user config stores in ~/.micro for any form of state such as saved environments, 
   333  tokens, etc. It will always attempt to read from here unless specified otherwise. Currently we store all 
   334  config in a single file `config.json` and any auth tokens in a `tokens` file.
   335  
   336  ## Environments
   337  
   338  Micro is built with a federated and multi-environment model in mind. Our development normally maps through local, staging and production, so Micro takes 
   339  this forward looking view and builds in the notion of environments which are completely isolated micro environments you can interact with through the CLI. 
   340  This reference explains environments.
   341  
   342  ### View Current
   343  
   344  Environments can be displayed using the `micro env` command.
   345  
   346  ```sh
   347  $ micro env
   348  * local      127.0.0.1:8081
   349    dev        proxy.m3o.dev
   350    platform   proxy.m3o.com
   351  ```
   352  
   353  There are three builtin environments, `local` being the default, and two [`m3o` specific](m3o.com) offerings; dev and platform.
   354  These exist for convenience and speed of development. Additional environments can be created using `micro env add [name] [host:port]`. 
   355  Environment addresses point to the micro proxy which defaults to :8081.
   356  
   357  ### Add Environment
   358  
   359  The command `micro env --help` provides a summary of usage. Here's an example of how to add an environment.
   360  
   361  ```sh
   362  $ micro env add foobar example.com
   363  $ micro env
   364  * local      127.0.0.1:8081
   365    dev        proxy.m3o.dev
   366    platform   proxy.m3o.com
   367    foobar     example.com
   368  ```
   369  
   370  ### Set Environment
   371  
   372  The `*` marks which environment is selected. Let's select the newly added:
   373  
   374  ```sh
   375  $ micro env set foobar
   376  $ micro env
   377    local      127.0.0.1:8081
   378    dev        proxy.m3o.dev
   379    platform   proxy.m3o.com
   380  * foobar     example.com
   381  ```
   382  
   383  ### Login to an Environment
   384  
   385  Each environment is effectively an isolated deployment with its own authentication, storage, etc. So each env requires signup and login. At this point we have to log in to the `example` env with `micro login`. If you don't have credentials to the environment, you have to ask the admin.
   386  
   387  ### Web Dashboard
   388  
   389  View and query services in a web browser at localhost:8082. The web dashboard is a simple 
   390  layer on top of the system to visualise services and their endpoints. Additionally it generates 
   391  dynamic forms for easy querying.
   392  
   393  Run the dashboard with the command
   394  ```
   395  micro web
   396  ```
   397  
   398  ## Services
   399  
   400  Micro is built as a distributed operating system leveraging the microservices architecture pattern.
   401  
   402  ### Overview
   403  
   404  Below we describe the list of services provided by the Micro Server. Each service is considered a 
   405  building block primitive for a platform and distributed systems development. The proto 
   406  interfaces for each can be found in [micro/proto/auth](https://github.com/tickoalcantara12/micro/blob/master/proto/auth/auth.proto) 
   407  and the Go library, client and server implementations in [micro/service/auth](https://github.com/tickoalcantara12/micro/tree/master/service/auth).
   408  
   409  ### API
   410  
   411  The API service is a http API gateway which acts as a public entrypoint and converts http/json to RPC.
   412  
   413  #### Overview
   414  
   415  The micro API is the public entrypoint for all external access to services to be consumed by frontend, mobile, etc. The api 
   416  accepts http/json requests and uses path based routing to resolve to backend services. It converts the request to gRPC and 
   417  forward appropriately. The idea here is to focus on microservices on the backend and stitch everything together as a single 
   418  API for the frontend. 
   419  
   420  #### Usage
   421  
   422  In the default `local` [environment](#environments) the API address is `127.0.0.1:8080`.
   423  Each service running is callable through this API.
   424  
   425  ```sh
   426  $ curl http://127.0.0.1:8080/
   427  {"version": "v3.0.0-beta"}
   428  ```
   429  
   430  An example call would be listing services in the registry:
   431  
   432  ```sh
   433  $ curl http://127.0.0.1:8080/registry/listServices
   434  ```
   435  
   436  The format is 
   437  ```
   438  curl http://127.0.0.1:8080/[servicename]/[endpointName]
   439  ```
   440  
   441  The endpoint name is lower camelcase.
   442  
   443  The parameters can be passed on as query params
   444  
   445  ```sh
   446  $ curl http://127.0.0.1:8080/helloworld/call?name=Joe
   447  {"msg":"Hello Joe"}
   448  ```
   449  
   450  or JSON body:
   451  
   452  ```sh
   453  curl -XPOST --header "Content-Type: application/json" -d '{"name":"Joe"}' http://127.0.0.1:8080/helloworld/call
   454  {"msg":"Hello Joe"}
   455  ```
   456  
   457  To specify a namespace when calling the API, the `Micro-Namespace` header can be used:
   458  
   459  ```sh
   460  $ curl -H "Micro-Namespace: foobar" http://127.0.0.1:8080/helloworld/call?name=Joe
   461  ```
   462  
   463  To call a [non-public service/endpoint](#auth), the `Authorization` header can be used:
   464  
   465  ```sh
   466  MICRO_API_TOKEN=`micro user token`
   467  curl -H "Authorization: Bearer $MICRO_API_TOKEN" http://127.0.0.1:8080/helloworld/call?name=Joe
   468  ```
   469  
   470  ### Auth
   471  
   472  The auth service provides both authentication and authorization.
   473  
   474  #### Overview
   475  
   476  The auth service stores accounts and access rules. It provides the single source of truth for all authentication 
   477  and authorization within the Micro runtime. Every service and user requires an account to operate. When a service 
   478  is started by the runtime an account is generated for it. Core services and services run by Micro load rules 
   479  periodically and manage the access to their resources on a per request basis.
   480  
   481  #### Usage
   482  
   483  For CLI command help use `micro auth --help` or auth subcommand help such as `micro auth create --help`.
   484  
   485  #### Login
   486  
   487  To login to a server simply so the following
   488  
   489  ```
   490  $ micro login
   491  Enter username: admin
   492  Enter password: 
   493  Successfully logged in.
   494  ```
   495  
   496  Assuming you are pointing to the right environment. It defaults to the local `micro server`.
   497  
   498  #### Rules
   499  
   500  Rules determine what resource a user can access. The default rule is the following:
   501  
   502  ```sh
   503  $ micro auth list rules
   504  ID          Scope           Access      Resource        Priority
   505  default     <public>        GRANTED     *:*:*           0
   506  ```
   507  
   508  The `default` rule makes all services callable that appear in the `micro status` output.
   509  Let's see an example of this.
   510  
   511  ```sh
   512  $ micro run helloworld
   513  # Wait for the service to accept calls
   514  $ curl 127.0.0.1:8080/helloworld/call?name=Alice
   515  {"msg":"Hello Alice"}
   516  ```
   517  
   518  If we want to prevent unauthorized users from calling our services, we can create the following rule
   519  
   520  ```sh
   521  # This command creates a rule that enables only logged in users to call the micro server
   522  micro auth create rule  --access=granted --scope='*' --resource="*:*:*" onlyloggedin
   523  # Create the rule which allows us to login
   524  micro auth create rule --access=granted --resource="service:auth:*" auth-public
   525  ```
   526  
   527  and delete the default one.
   528  Here, the scope `*` is markedly different from the `<public>` scope we have seen earlier when doing a `micro auth list rules`:
   529  
   530  ```sh
   531  $ micro auth list rules
   532  ID            Scope         Access       Resource       Priority
   533  auth-public   <public>      GRANTED      service:auth:* 0
   534  onlyloggedin  *             GRANTED      *:*:*          0
   535  default       <public>      GRANTED      *:*:*          0
   536  ```
   537  
   538  Now, let's remove the default rule.
   539  
   540  ```sh
   541  # This command deletes the 'default' rule - the rule which enables anyone to call the 'micro server'.
   542  $ micro auth delete rule default
   543  Rule deleted
   544  ```
   545  
   546  Let's try curling our service again:
   547  
   548  ```sh
   549  $ curl 127.0.0.1:8080/helloworld/call?name=Alice
   550  {"Id":"helloworld","Code":401,"Detail":"Unauthorized call made to helloworld:Helloworld.Call","Status":"Unauthorized"}
   551  ```
   552  
   553  Our `onlyloggedin` rule took effect. We can still call the service with a token:
   554  
   555  ```sh
   556  $ token=$(micro user token)
   557  # Locally:
   558  # curl "Authorization: Bearer $token" 127.0.0.1:8080/helloworld/call?name=Alice
   559  {"msg":"Hello Alice"}
   560  ```
   561  
   562  (Please note tokens have a limited lifetime so the line `$ token=$(micro user token)` has to be reissued from time to time, or the command must be used inline.)
   563  
   564  #### Accounts
   565  
   566  Auth service supports the concept of accounts. The default account used to access the `micro server` is the admin account.
   567  
   568  ```sh
   569  $ micro auth list accounts
   570  ID		Name		Scopes		Metadata
   571  admin		admin		admin		n/a
   572  ```
   573  
   574  We can create accounts for teammates and coworkers with `micro auth create account`:
   575  
   576  ```sh
   577  $ micro auth create account --scopes=admin jane
   578  Account created: {"id":"jane","type":"","issuer":"micro","metadata":null,"scopes":["admin"],"secret":"bb7c1a96-c0c6-4ff5-a0e9-13d456f3db0a","name":"jane"}
   579  ```
   580  
   581  The freshly created account can be used with `micro login` by using the `jane` id and `bb7c1a96-c0c6-4ff5-a0e9-13d456f3db0a` password.
   582  
   583  ### Broker
   584  
   585  The broker is a message broker for asynchronous pubsub messaging.
   586  
   587  #### Overview
   588  
   589  The broker provides a simple abstraction for pubsub messaging. It focuses on simple semantics for fire-and-forget 
   590  asynchronous communication. The goal here is to provide a pattern for async notifications where some update or 
   591  events occurred but that does not require persistence. The client and server build in the ability to publish 
   592  on one side and subscribe on the other. The broker provides no message ordering guarantees.
   593  
   594  While a Service is normally called by name, messaging focuses on Topics that can have multiple publishers and 
   595  subscribers. The broker is abstracting away in the service's client/server which includes message encoding/decoding 
   596  so you don't have to spend all your time marshalling.
   597  
   598  ##### Client
   599  
   600  The client contains the `Publish` method which takes a proto message, encodes it and publishes onto the broker 
   601  on a given topic. It takes the metadata from the client context and includes these as headers in the message 
   602  including the content-type so the subscribe side knows how to deal with it.
   603  
   604  ##### Server
   605  
   606  The server supports a `Subscribe` method which allows you to register a handler as you would for handling requests. 
   607  In this way we can mirror the handler behaviour and deserialize the message when consuming from the broker. In 
   608  this model the server handles connecting to the broker, subscribing, consuming and executing your subscriber
   609  function.
   610  
   611  #### Usage
   612  
   613  Publisher:
   614  ```go
   615  bytes, err := json.Marshal(&Healthcheck{
   616  	Healthy: true,
   617  	Service: "foo",
   618  })
   619  if err != nil {
   620  	return err
   621  }
   622  
   623  return broker.Publish("health", &broker.Message{Body: bytes})
   624  ```
   625  
   626  Subscriber:
   627  ```go
   628  handler := func(msg *broker.Message) error {
   629  	var hc Healthcheck
   630  	if err := json.Unmarshal(msg.Body, &hc); err != nil {
   631  		return err
   632  	}
   633  	
   634  	if hc.Healthy {
   635  		logger.Infof("Service %v is healthy", hc.Service)
   636  	} else {
   637  		logger.Infof("Service %v is not healthy", hc.Service)
   638  	}
   639  
   640  	return nil
   641  }
   642  
   643  sub, err := broker.Subscribe("health", handler)
   644  if err != nil {
   645  	return err
   646  }
   647  ```
   648  
   649  ### Config
   650  
   651  The config service provides dynamic configuration for services. 
   652  
   653  #### Overview
   654  
   655  Config can be stored and loaded separately to 
   656  the application itself for configuring business logic, api keys, etc. We read and write these as key-value 
   657  pairs which also support nesting of JSON values. The config interface also supports storing secrets by 
   658  defining the secret key as an option at the time of writing the value.
   659  
   660  #### Usage
   661  
   662  Let's assume we have a service called `helloworld` from which we want to read configuration data.
   663  First we have to insert said data with the cli. Config data can be organized under different "paths" with the dot notation.
   664  It's a good convention to save all config data belonging to a service under a top level path segment matching the service name:
   665  
   666  ```sh
   667  $ micro config set helloworld.somekey hello
   668  $ micro config get helloworld.somekey
   669  hello
   670  ```
   671  
   672  We can save another key too and read all values in one go with the dot notation:
   673  
   674  ```sh
   675  $ micro config set helloworld.someotherkey "Hi there!"
   676  $ micro config get helloworld
   677  {"somekey":"hello","someotherkey":"Hi there!"}
   678  ```
   679  
   680  As it can be seen, the config (by default) stores configuration data as JSONs.
   681  We can save any type:
   682  
   683  ```sh
   684  $ micro config set helloworld.someboolkey true
   685  $ micro config get helloworld.someboolkey
   686  true
   687  $ micro config get helloworld
   688  {"someboolkey":true,"somekey":"hello","someotherkey":"Hi there!"}
   689  ```
   690  
   691  So far we have only saved top level keys. Let's explore the advantages of the dot notation.
   692  
   693  ```sh
   694  $ micro config set helloworld.keywithsubs.subkey1 "So easy!"
   695  {"keywithsubs":{"subkey1":"So easy!"},"someboolkey":true,"somekey":"hello","someotherkey":"Hi there!"}
   696  ```
   697  
   698  Some of the example keys are getting in our way, let's learn how to delete:
   699  
   700  ```sh
   701  $ micro config del helloworld.someotherkey
   702  $ micro config get helloworld
   703  {"keywithsubs":{"subkey1":"So easy!"},"someboolkey":true,"somekey":"hello"}
   704  ```
   705  
   706  We can of course delete not just `leaf` level keys, but top level ones too:
   707  
   708  ```sh
   709  $ micro config del helloworld.keywithsubs
   710  $ micro config get helloworld
   711  {"someboolkey":true,"somekey":"hello"}
   712  ```
   713  
   714  ##### Secrets
   715  
   716  The config also supports secrets - values encrypted at rest. This helps in case of leaks, be it a security one or an accidental copy paste.
   717  
   718  They are fairly easy to save:
   719  
   720  ```sh
   721  $ micro config set --secret helloworld.hushkey "Very secret stuff" 
   722  $ micro config get helloworld.hushkey
   723  [secret]
   724  
   725  $ micro config get --secret helloworld.hushkey
   726  Very secret stuff
   727  
   728  $ micro config get helloworld
   729  {"hushkey":"[secret]","someboolkey":true,"somekey":"hello"}
   730  
   731  $ micro config get --secret helloworld
   732  {"hushkey":"Very secret stuff","someboolkey":true,"somekey":"hello"}
   733  ```
   734  
   735  Even bool or number values can be saved as secrets, and they will appear as the string constant `[secret]` unless decrypted:
   736  
   737  ```sh
   738  $ micro config set --secret helloworld.hush_number_key 42
   739  $ micro config get helloworld
   740  {"hush_number_key":"[secret]","hushkey":"[secret]","someboolkey":true,"somekey":"hello"}
   741  
   742  $ micro config get --secret helloworld
   743  {"hush_number_key":42,"hushkey":"Very secret stuff","someboolkey":true,"somekey":"hello"}
   744  ```
   745  
   746  #### Service Framework
   747  
   748  It is similarly easy to access and set config values from a service.
   749  A good example of reading values is [the config example test service](https://github.com/micro/services/blob/master/test/conf):
   750  
   751  ```go
   752  package main
   753  
   754  import (
   755  	"fmt"
   756  	"time"
   757  
   758  	"github.com/tickoalcantara12/micro/v3/service"
   759  	"github.com/tickoalcantara12/micro/v3/service/config"
   760  )
   761  
   762  type keyConfig struct {
   763  	Subkey  string `json:"subkey"`
   764  	Subkey1 int    `json:"subkey1"`
   765  }
   766  
   767  type conf struct {
   768  	Key keyConfig `json:"key"`
   769  }
   770  
   771  func main() {
   772  	go func() {
   773  		for {
   774  			time.Sleep(time.Second)
   775  			val, err := config.Get("key.subkey")
   776  			fmt.Println("Value of key.subkey: ", val.String(""), err)
   777  
   778  			val, err = config.Get("key", config.Secret(true))
   779  			if err != nil {
   780  				fmt.Println(err)
   781  			}
   782  			c := conf{}
   783  			err = val.Scan(&c.Key)
   784  			fmt.Println("Value of key.subkey1: ", c.Key.Subkey1, err)
   785  		}
   786  	}()
   787  
   788  	// run the service
   789  	service.Run()
   790  }
   791  ```
   792  
   793  The above service will print the value of `key.subkey` and `key.subkey` every second.
   794  By passing in the `config.Secret(true)` option, we tell config to decrypt secret values for us, similarly to the `--secret` CLI flag.
   795  
   796  The [config interface](https://github.com/tickoalcantara12/micro/blob/master/service/config/config.go) specifies not just `Get` `Set` and `Delete` to access values,
   797  but a few convenience functions too in the `Value` interface.
   798  
   799  It is worth noting that `String` `Int` etc methods will do a best effort try at coercing types, ie. if the value saved is a string, `Int` will try to parse it.
   800  However, the same does not apply to the `Scan` method, which uses `json.Unmarshal` under the hood, which we all know fails when encountering type mismatches.
   801  
   802  `Get` should, in all cases, return a non nil `Value`, so even if the `Get` errors, `Value.Int()` and other operations should never panic.
   803  
   804  #### Advanced Concepts
   805  
   806  ##### Merging Config Values
   807  
   808  When saving a string with the CLI that is a valid JSON map, it gets expanded to be saved as a proper map structure, instead of a string, ie
   809  
   810  ```sh
   811  $ micro config set helloworld '{"a": "val1", "b": "val2"}'
   812  $ micro config get helloworld.a
   813  val1
   814  # If the string would be saved as is, `helloworld.a` would be a nonexistent path
   815  ```
   816  
   817  The advantages of this become particularly visible when `Set`ting a complex type with the library:
   818  
   819  ```go
   820  type conf struct {
   821  	A string `json:"a"`
   822  	B string `json:"b"`
   823  }
   824  
   825  c1 := conf{"val1", "val2"}
   826  config.Set("key", c1)
   827  
   828  v, _ := config.Get("key")
   829  c2 := &conf{}
   830  v.Scan(c2)
   831  // c1 and c2 should be equal
   832  ```
   833  
   834  Or with the following example
   835  
   836  ```sh
   837  $ micro config del helloworld
   838  $ micro config set helloworld '{"a":1}'
   839  $ micro config get helloworld
   840  {"a":1}
   841  $ micro config set helloworld '{"b":2}'
   842  $ micro config get helloworld
   843  {"a":1,"b":2}
   844  ```
   845  
   846  #### Secret encryption keys for `micro server`
   847  
   848  By default, if not specified, `micro server` generates and saves an encryption key to the location `~/.micro/config_secret_key`. This is intended for local zero dependency use, but not for production.
   849  
   850  To specify the secret for the micro server either the env var `MICRO_CONFIG_SECRET_KEY` or the flag `config_secret_key` key must be specified.
   851  
   852  ### Errors
   853  
   854  The errors package provides error types for most common HTTP status codes, e.g. BadRequest, InternalServerError etc. It's recommended when returning an error to an RPC handler, one of these errors is used. If any other type of error is returned, it's treated as an InternalServerError.
   855  
   856  Micro API detects these error types and will use them to determine the response status code. For example, if your handler returns errors.BadRequest, the API will return a 400 status code. If no error is returned the API will return the default 200 status code.
   857  
   858  Error codes are also used when handling retries. If your service returns a 500 (InternalServerError) or 408 (Timeout) then the client will retry the request. Other status codes are treated as client error and won't be retried.
   859  
   860  #### Usage
   861  
   862  ```go
   863  import (
   864  	"github.com/tickoalcantara12/micro/v3/service/errors"
   865  )
   866  
   867  func (u *Users) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error {
   868  	if len(req.Id) == 0 {
   869  		return errors.BadRequest("users.Read.MissingID", "Missing ID")
   870  	}
   871  
   872  	...
   873  }
   874  ```
   875  
   876  ### Events
   877  
   878  The events service is a service for event streaming and persistent storage of events.
   879  
   880  #### Overview
   881  
   882  Event streaming differs from pubsub messaging in that it provides an ordered stream of events that can be consumed 
   883  or replayed from any given point in the past. If you have experience with Kafka then you know it's basically a 
   884  distributed log which allows you to read a file from different offsets and stream it.
   885  
   886  The event service and interface provide the event streaming abstraction for writing and reading events along with 
   887  consuming from any given offset. It also supports acking and error handling where appropriate.
   888  
   889  Events also different from the broker in that it provides a fixed Event type where you fill in the details and 
   890  handle the decoding of the message body yourself. Events could have large payloads so we don't want to 
   891  unnecessarily decode where you may just want to hand off to a storage system.
   892  
   893  #### Functions
   894  
   895  The events package has two parts: Stream and Store. Stream is used to Publish and Consume to messages for a given topic. For example, in a chat application one user would Publish a message and another would subscribe. If you later needed to retrieve messages, you could either replay them using the Subscribe function and passing the Offset option, or list them using the Read function.
   896  
   897  ```go
   898  func Publish(topic string, msg interface{}, opts ...PublishOption) error 
   899  ```
   900  The Publish function has two required arguments: topic and message. Topic is the channel you're publishing the event to, in the case of a chat application this would be the chat id. The message is any struct, e.g. the message being sent to the chat. When the subscriber receives the event they'll be able to unmarshal this object. Publish has two supported options, WithMetadata to pass key/value pairs and WithTimestamp to override the default timestamp on the event.
   901  
   902  ```go
   903  func Consume(topic string, opts ...ConsumeOption) (<-chan Event, error)
   904  ```
   905  The Consume function is used to consume events. In the case of a chat application, the client would pass the chat ID as the topic, and any events published to the stream will be sent to the event channel. Event has an Unmarshal function which can be used to access the message payload, as demonstrated below:
   906  
   907  ```go
   908  for {
   909  	evChan, err := events.Consume(chatID)
   910  	if err != nil {
   911  		logger.Error("Error subscribing to topic %v: %v", chatID, err)
   912  		return err
   913  	}
   914  	for {
   915  		ev, ok := <- evChan
   916  		if !ok {
   917  			break
   918  		}
   919  		var msg Message
   920  		if err :=ev.Unmarshal(&msg); err != nil {
   921  			logger.Errorf("Error unmarshaling event %v: %v", ev.ID, err)
   922  			return err
   923  		}
   924  		logger.Infof("Received message: %v", msg.Subject)
   925  	}
   926  }
   927  ```
   928  
   929  #### Example
   930  
   931  The [Chat Service](https://github.com/micro/services/tree/master/test/chat) examples usage of the events service, leveraging both the stream and store functions.
   932  
   933  ### Network
   934  
   935  The network is a service to service network for request proxying
   936  
   937  #### Overview
   938  
   939  The network provides a service to service networking abstraction that includes proxying, authentication, 
   940  tenancy isolation and makes use of the existing service discovery and routing system. The goal here 
   941  is not to provide service mesh but a higher level control plane for routing that can govern access 
   942  based on the existing system. The network requires every service to be pointed to it, making 
   943  an explicit choice for routing.
   944  
   945  Beneath the covers cilium, envoy and other service mesh tools can be used to provide a highly 
   946  resilient mesh.
   947  
   948  ### Registry
   949  
   950  The registry is a service directory and endpoint explorer
   951  
   952  #### Overview
   953  
   954  The service registry provides a single source of truth for all services and their APIs. All services 
   955  on startup will register their name, version, address and endpoints with the registry service. They 
   956  then periodically re-register to "heartbeat", otherwise being expired based on a pre-defined TTL 
   957  of 90 seconds. 
   958  
   959  The goal of the registry is to allow the user to explore APIs and services within a running system.
   960  
   961  The simplest form of access is the below command to list services.
   962  
   963  ```
   964  micro services
   965  ```
   966  
   967  #### Usage
   968  
   969  The get service endpoint returns information about a service including response parameters parameters for endpoints:
   970  
   971  ```sh
   972  $ micro registry getService --service=helloworld
   973  {
   974  	"services": [
   975  		{
   976  			"name": "helloworld",
   977  			"version": "latest",
   978  			"metadata": {
   979  				"domain": "micro"
   980  			},
   981  			"endpoints": [
   982  				{
   983  					"name": "Helloworld.Call",
   984  					"request": {
   985  						"name": "CallRequest",
   986  						"type": "CallRequest",
   987  						"values": [
   988  							{
   989  								"name": "name",
   990  								"type": "string",
   991  								"values": []
   992  							}
   993  						]
   994  					},
   995  					"response": {
   996  						"name": "CallResponse",
   997  						"type": "CallResponse",
   998  						"values": [
   999  							{
  1000  								"name": "message",
  1001  								"type": "string",
  1002  								"values": []
  1003  							}
  1004  						]
  1005  					},
  1006  					"metadata": {}
  1007  				},
  1008  				{
  1009  					"name": "Helloworld.Stream",
  1010  					"request": {
  1011  						"name": "Context",
  1012  						"type": "Context",
  1013  						"values": []
  1014  					},
  1015  					"response": {
  1016  						"name": "Stream",
  1017  						"type": "Stream",
  1018  						"values": []
  1019  					},
  1020  					"metadata": {
  1021  						"stream": "true"
  1022  					}
  1023  				}
  1024  			],
  1025  			"nodes": [
  1026  				{
  1027  					"id": "helloworld-3a0d02be-f98e-4d9d-a8fa-24e942580848",
  1028  					"address": "192.168.43.193:34321",
  1029  					"port": "0",
  1030  					"metadata": {
  1031  						"broker": "service",
  1032  						"protocol": "grpc",
  1033  						"registry": "service",
  1034  						"server": "grpc",
  1035  						"transport": "grpc"
  1036  					}
  1037  				}
  1038  			],
  1039  			"options": {
  1040  				"ttl": "0",
  1041  				"domain": ""
  1042  			}
  1043  		}
  1044  	]
  1045  }
  1046  ```
  1047  
  1048  This is an especially useful feature for writing custom meta tools like API explorers.
  1049  
  1050  ### Runtime
  1051  
  1052  #### Overview
  1053  
  1054  The runtime service is responsible for running, updating and deleting binaries or containers (depending on the platform - eg. binaries locally, pods on k8s etc) and their logs.
  1055  
  1056  #### Running a service
  1057  
  1058  The `micro run` command tells the runtime to run a service. The following are all valid examples:
  1059  
  1060  ```sh
  1061  micro run github.com/micro/services/helloworld
  1062  micro run .  # deploy local folder to your local micro server
  1063  micro run ../path/to/folder # deploy local folder to your local micro server
  1064  micro run helloworld # deploy latest version, translates to micro run github.com/micro/services/helloworld or your custom base url
  1065  micro run helloworld@9342934e6180 # deploy certain version
  1066  micro run helloworld@branchname  # deploy certain branch
  1067  micro run --name helloworld .
  1068  ```
  1069  
  1070  #### Specifying Service Name
  1071  
  1072  The service name is derived from the directory name of your application. In case you want to override this specify the `--name` flag.
  1073  
  1074  ```
  1075  micro run --name helloworld github.com/myorg/helloworld/server
  1076  ```
  1077  
  1078  #### Running a local folder
  1079  
  1080  If the first parameter is an existing local folder, ie
  1081  
  1082  ```sh
  1083  micro run ./foobar
  1084  ```
  1085  
  1086  Then the CLI will upload that folder to the runtime and the runtime runs that.
  1087  
  1088  #### Running a git source
  1089  
  1090  If the first parameter to `micro run` points to a git repository (be it on GitHub, GitLab, Bitbucket or any other provider), then the address gets sent to the runtime and the runtime downloads the code and runs it.
  1091  
  1092  ##### Using references
  1093  
  1094  References are the part of the first parameter passed to run after the `@` sign. It can either be a branch name (no reference means version `latest` which equals to master in git terminology) or a commit hash.
  1095  
  1096  When branch names are passed in, the latest commit of the code will run.
  1097  
  1098  #### Listing runtime objects
  1099  
  1100  The `micro status` command lists all things running in the runtime:
  1101  
  1102  ```sh
  1103  $ micro status
  1104  NAME		VERSION	SOURCE					STATUS	BUILD	UPDATED		METADATA
  1105  helloworld	latest	github.com/micro/services/helloworld	running	n/a	20h43m45s ago	owner=admin, group=micro
  1106  ```
  1107  
  1108  The output includes the error if there is one. Commands like `micro kill`, `micro logs`, `micro update` accept the name returned by the `micro status` as the first parameter (and not the service name as that might differ).
  1109  
  1110  #### Updating a service
  1111  
  1112  The `micro update` command makes the runtime pull the latest commit in the branch and restarts the service.
  1113  
  1114  In case of local code it requires not the runtime name (returned by `micro status`) but the local path. For commit hash deploys it just restarts the service.
  1115  
  1116  Examples: `micro update helloworld`, `micro update helloworld@branch`, `micro update helloworld@commit`, `micro update ./helloworld`.
  1117  
  1118  #### Deleting a service
  1119  
  1120  The `micro kill` command removes a runtime object from the runtime. It accepts the name returned by `micro status`.
  1121  
  1122  Examples: `micro kill helloworld`.
  1123  
  1124  #### Logs
  1125  
  1126  The `micro logs` command shows logs for a runtime object. It accepts the name returned by `micro status`.
  1127  
  1128  The `-f` flag makes the command stream logs continuously.
  1129  
  1130  Examples: `micro logs helloworld`, `micro logs -f helloworld`.
  1131  
  1132  ### Store
  1133  
  1134  Micro's store interface is for persistent key-value storage.
  1135  
  1136  For a good beginner level doc on the Store, please see the [Getting started tutorial](/getting-started#storage).
  1137  
  1138  #### Overview
  1139  
  1140  Key-value stores that support ordering of keys can be used to build complex applications.
  1141  Due to their very limited feature set, key-value stores generally scale easily and reliably, often linearly with the number of nodes added.
  1142  
  1143  This scalability comes at the expense of inconvenience and mental overhead when writing business logic. For use cases where linear scalability is important, this trade-off is preferred.
  1144  
  1145  #### Query by ID
  1146  
  1147  Reading by ID is the archetypal job for key value stores. Storing data to enable this ID works just like in any other database:
  1148  
  1149  ```sh
  1150  # entries designed for querying "users by id"
  1151  KEY         VALUE
  1152  id1         {"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1153  id2         {"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1154  id3         {"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1155  id4         {"id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
  1156  ```
  1157  
  1158  ```go
  1159  import "github.com/tickoalcantara12/micro/v3/service/store"
  1160  
  1161  records, err := store.Read("id1")
  1162  if err != nil {
  1163  	fmt.Println("Error reading from store: ", err)
  1164  }
  1165  fmt.Println(records[0].Value)
  1166  // Will output {"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1167  ```
  1168  
  1169  Given this data structure, we can do two queries:
  1170  
  1171  - reading a given key (get "id1", get "id2")
  1172  - if the keys are ordered, we can ask for X number of entries after a key (get 3 entries after "id2")
  1173  
  1174  Finding values in an ordered set is possibly the simplest task we can ask a database.
  1175  The problem with the above data structure is that it's not very useful to ask "find me keys coming in the order after "id2". To enable other kinds of queries, the data must be saved with different keys.
  1176  
  1177  In the case of the schoold students, let's say we wan't to list by class. To do this, having the query in mind, we can copy the data over to another table named after the query we want to do:
  1178  
  1179  #### Query by Field Value Equality
  1180  
  1181  ```sh
  1182  # entries designed for querying "users by class"
  1183  KEY             VALUE
  1184  firstGrade/id1  {"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1185  secondGrade/id2 {"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1186  secondGrade/id3 {"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1187  thirdGrade/id4  {"id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
  1188  ```
  1189  
  1190  
  1191  ```go
  1192  import "github.com/tickoalcantara12/micro/v3/service/store"
  1193  
  1194  records, err := store.Read("", store.Prefix("secondGrade"))
  1195  if err != nil {
  1196  	fmt.Println("Error reading from store: ", err)
  1197  }
  1198  fmt.Println(records[0].Value)
  1199  // Will output
  1200  // secondGrade/id2 {"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1201  // secondGrade/id3 {"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1202  ```
  1203  
  1204  Since the keys are ordered it is very trivial to get back let's say "all second graders".
  1205  Key value stores which have their keys ordered support something similar to "key starts with/key has prefix" query. In the case of second graders, listing all records where the "keys start with `secondGrade`" will give us back all the second graders.
  1206  
  1207  This query is basically a `field equals to` as we essentially did a `field class == secondGrade`. But we could also exploit the ordered nature of the keys to do a value comparison query, ie `field avgScores is less than 90` or `field AvgScores is between 90 and 95` etc., if we model our data appropriately:
  1208  
  1209  #### Query for Field Value Ranges
  1210  
  1211  ```sh
  1212  # entries designed for querying "users by avgScore"
  1213  KEY         VALUE
  1214  089/id3     {"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1215  092/id2     {"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1216  094/id4     {"id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
  1217  098/id1     {"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1218  ```
  1219  
  1220  It's worth remembering that the keys are strings, and that they are ordered lexicographically. For this reason when dealing with numbering values, we must make sure that they are prepended to the same length appropriately.
  1221  
  1222  At the moment Micro's store does not support this kind of query, this example is only here to hint at future possibilities with the store.
  1223  
  1224  #### Tables Usage
  1225  
  1226  Micro services only have access to one Store table. This means all keys live in the same namespace and can collide. A very useful pattern is to separate the entries by their intended query pattern, ie taking the "users by id" and users by class records above:
  1227  
  1228  ```sh
  1229  KEY         VALUE
  1230  # entries designed for querying "users by id"
  1231  usersById/id1         		{"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1232  usersById/id2         		{"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1233  usersById/id3         		{"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1234  usersById/id4         		{"id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
  1235  # entries designed for querying "users by class"
  1236  usersByClass/firstGrade/id1  {"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1237  usersByClass/secondGrade/id2 {"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1238  usersByClass/secondGrade/id3 {"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1239  usersByClass/thirdGrade/id4  {"id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
  1240  ```
  1241  
  1242  Respective go examples this way become:
  1243  
  1244  ```go
  1245  import "github.com/tickoalcantara12/micro/v3/service/store"
  1246  
  1247  const idPrefix = "usersById/"
  1248  
  1249  records, err := store.Read(idPrefix + "id1")
  1250  if err != nil {
  1251  	fmt.Println("Error reading from store: ", err)
  1252  }
  1253  fmt.Println(records[0].Value)
  1254  // Will output {"id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
  1255  ```
  1256  
  1257  ```go
  1258  import "github.com/tickoalcantara12/micro/v3/service/store"
  1259  
  1260  const classPrefix = "usersByClass/"
  1261  
  1262  records, err := store.Read("", store.Prefix(classPrefix + "secondGrade"))
  1263  if err != nil {
  1264  	fmt.Println("Error reading from store: ", err)
  1265  }
  1266  fmt.Println(records[0].Value)
  1267  // Will output
  1268  // secondGrade/id2 {"id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
  1269  // secondGrade/id3 {"id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
  1270  ```
  1271  
  1272  ### Metadata
  1273  
  1274  Metadata / headers can be passed via the context in RPC calls. The context/metadata package allows services to get and set metadata in a context. The Micro API will add request headers into context, for example if the "Foobar" header is set on an API call to "localhost:8080/users/List", the users service can access this value as follows:
  1275  
  1276  ```go
  1277  import (
  1278  	"context"
  1279  	"github.com/tickoalcantara12/micro/v3/service/context/metadata"
  1280  )
  1281  
  1282  ...
  1283  
  1284  func (u *Users) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
  1285  	val, ok := metadata.Get(ctx, "Foobar")
  1286  	if !ok {
  1287  		return fmt.Errorf("Missing Foobar header")
  1288  	}
  1289  
  1290  	fmt.Println("Foobar header was set to: %v", val)
  1291  	return nil
  1292  }
  1293  ```
  1294  
  1295  Likewise, clients can set metadata in context using the metadata.Set function as follows:
  1296  
  1297  ```go
  1298  func (u *Users) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
  1299  	newCtx := metadata.Set(ctx, "Foobar", "mycustomval")
  1300  	fRsp, err := u.foosrv.Call(newCtx, &foosrv.Request{})
  1301  	...
  1302  }
  1303  ```
  1304  
  1305  ## Plugins
  1306  
  1307  Micro is a pluggable architecture built on Go's interface types. Plugins enable swapping out underlying infrastructure.
  1308  
  1309  ### Overview
  1310  
  1311  Micro is pluggable, meaning the implementation for each module can be replaced depending on the requirements. Plugins are applied to the micro server and not to services directly, this is done so the underlying infrastructure can change with zero code changes required in your services. 
  1312  
  1313  An example of a pluggable interface is the store. Locally micro will use a filestore to persist data, this is great because it requires zero dependencies and still offers persistence between restarts. When running micro in a test suite, this could be swapped to an in-memory cache which is better suited as it offers consistency between runs. In production, this can be swapped out for standalone infrastructure such as cockroachdb or etcd depending on the requirement.
  1314  
  1315  Let's take an example where our service wants to load data from the store. Our service would call `store.Read(userPrefix + userID)` to load the value, behind the scenes this will execute an RPC to the store service which will in-turn call `store.Read` on the current `DefaultStore` implementation configured for the server. 
  1316  
  1317  ### Profiles
  1318  
  1319  Profiles are used to configure multiple plugins at once. Micro comes with a few profiles out the box, such as "local", "kubernetes" and "test". These profiles can be found in `profile/profile.go`. You can configure micro to use one of these profiles using the `MICRO_PROFILE` env var, for example: `MICRO_PROFILE=test micro server`. The default profile used is "local".
  1320  
  1321  ### Writing a profile
  1322  
  1323  Profiles should be created as packages within the profile directory. Let's create a "staging" profile by creating `profile/staging/staging.go`. The example below shows how to override the default store of `Local` profile to use an in-memory implementation:
  1324  
  1325  ```go
  1326  // Package staging configures micro for a staging environment
  1327  package staging
  1328  
  1329  import (
  1330  	"github.com/urfave/cli/v2"
  1331  
  1332  	"github.com/tickoalcantara12/micro/v3/profile"
  1333  	"github.com/tickoalcantara12/micro/v3/service/store"
  1334  	"github.com/tickoalcantara12/micro/v3/service/store/memory"
  1335  )
  1336  
  1337  func init() {
  1338  	profile.Register("staging", staging)
  1339  }
  1340  
  1341  var staging = &profile.Profile{
  1342  	Name: "staging",
  1343  	Setup: func(ctx *cli.Context) error {
  1344  		profile.Local.Setup(ctx)
  1345  		store.DefaultStore = memory.NewStore()
  1346  		return nil
  1347  	},
  1348  }
  1349  ```
  1350  
  1351  ```bash
  1352  pushd profile/staging
  1353  go mod init github.com/tickoalcantara12/micro/profile/staging
  1354  go mod tidy
  1355  popd
  1356  ```
  1357  
  1358  ### Using a custom profile
  1359  
  1360  You can load a custom profile using a couple of commands, the first adds a replace to your go mod, indicating it should look for your custom profile within the profile directory:
  1361  
  1362  ```bash
  1363  go mod edit -replace github.com/tickoalcantara12/micro/profile/staging/v3=./profile/staging
  1364  go mod tidy
  1365  ```
  1366  
  1367  The second command creates a profile.go file which imports your profile. When your profile is imported, the init() function which is defined in staging.go is called, registering your profile.
  1368  
  1369  ```
  1370  micro init --profile=staging --output=profile.go
  1371  ```
  1372  
  1373  Now you can start your server using this profile:
  1374  ```
  1375  MICRO_PROFILE=staging go run . server
  1376  ```
  1377