`Devspace`: Managing Apps in Kubernetes
What is devspace?
devspace is a CLI tool for kubernetes, which can help you configure, deploy, debug. and test your application inside Kubernetes.
DevSpace allows you to
- Store all your workflows in one declarative config file: 
devspace.yaml - Standardize deployment and development workflows without requiring everyone on the team to become a Kubernetes expert.
 - DevSpace allows you to hot reload running containers while coding
 
Read more about devspace here
Looking the official diagram from devspace which shows the benefits in detail

In this blog I will use devspace, rancher-desktop and k3d for quickly deploying a local application developed in previous blogs (Spinnaker-Hellow).
Step 1: Create a local cluster
We will be using k3d to create cluster
Options
k3d cluster create -h
Create a new k3s cluster with containerized nodes (k3s in docker).
Every cluster will consist of one or more containers:
	- 1 (or more) server node container (k3s)
	- (optionally) 1 loadbalancer container as the entrypoint to the cluster (nginx)
	- (optionally) 1 (or more) agent node containers (k3s)
Usage:
  k3d cluster create NAME [flags]
Flags:
  -a, --agents int                                                     Specify how many agents you want to create
      --agents-memory string                                           Memory limit imposed on the agents nodes [From docker]
      --api-port [HOST:]HOSTPORT                                       Specify the Kubernetes API server port exposed on the LoadBalancer (Format: [HOST:]HOSTPORT)
                                                                        - Example: `k3d cluster create --servers 3 --api-port 0.0.0.0:6550`
  -c, --config string                                                  Path of a config file to use
  -e, --env KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]                   Add environment variables to nodes (Format: KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]
                                                                        - Example: `k3d cluster create --agents 2 -e "HTTP_PROXY=my.proxy.com@server:0" -e "SOME_KEY=SOME_VAL@server:0"`
      --gpus string                                                    GPU devices to add to the cluster node containers ('all' to pass all GPUs) [From docker]
  -h, --help                                                           help for create
      --host-alias ip:host[,host,...]                                  Add ip:host[,host,...] mappings
      --host-pid-mode                                                  Enable host pid mode of server(s) and agent(s)
  -i, --image string                                                   Specify k3s image that you want to use for the nodes
      --k3s-arg ARG@NODEFILTER[;@NODEFILTER]                           Additional args passed to k3s command (Format: ARG@NODEFILTER[;@NODEFILTER])
                                                                        - Example: `k3d cluster create --k3s-arg "--disable=traefik@server:0"
      --k3s-node-label KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]        Add label to k3s node (Format: KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]
                                                                        - Example: `k3d cluster create --agents 2 --k3s-node-label "my.label@agent:0,1" --k3s-node-label "other.label=somevalue@server:0"`
      --kubeconfig-switch-context                                      Directly switch the default kubeconfig's current-context to the new cluster's context (requires --kubeconfig-update-default) (default true)
      --kubeconfig-update-default                                      Directly update the default kubeconfig with the new cluster's context (default true)
      --lb-config-override strings                                     Use dotted YAML path syntax to override nginx loadbalancer settings
      --network string                                                 Join an existing network
      --no-image-volume                                                Disable the creation of a volume for importing images
      --no-lb                                                          Disable the creation of a LoadBalancer in front of the server nodes
      --no-rollback                                                    Disable the automatic rollback actions, if anything goes wrong
  -p, --port [HOST:][HOSTPORT:]CONTAINERPORT[/PROTOCOL][@NODEFILTER]   Map ports from the node containers (via the serverlb) to the host (Format: [HOST:][HOSTPORT:]CONTAINERPORT[/PROTOCOL][@NODEFILTER])
                                                                        - Example: `k3d cluster create --agents 2 -p 8080:80@agent:0 -p 8081@agent:1`
      --registry-config string                                         Specify path to an extra registries.yaml file
      --registry-create NAME[:HOST][:HOSTPORT]                         Create a k3d-managed registry and connect it to the cluster (Format: NAME[:HOST][:HOSTPORT]
                                                                        - Example: `k3d cluster create --registry-create mycluster-registry:0.0.0.0:5432`
      --registry-use stringArray                                       Connect to one or more k3d-managed registries running locally
      --runtime-label KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]         Add label to container runtime (Format: KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]
                                                                        - Example: `k3d cluster create --agents 2 --runtime-label "my.label@agent:0,1" --runtime-label "other.label=somevalue@server:0"`
  -s, --servers int                                                    Specify how many servers you want to create
      --servers-memory string                                          Memory limit imposed on the server nodes [From docker]
      --subnet 172.28.0.0/16                                           [Experimental: IPAM] Define a subnet for the newly created container network (Example: 172.28.0.0/16)
      --timeout duration                                               Rollback changes if cluster couldn't be created in specified duration.
      --token string                                                   Specify a cluster token. By default, we generate one.
  -v, --volume [SOURCE:]DEST[@NODEFILTER[;NODEFILTER...]]              Mount volumes into the nodes (Format: [SOURCE:]DEST[@NODEFILTER[;NODEFILTER...]]
                                                                        - Example: `k3d cluster create --agents 2 -v /my/path@agent:0,1 -v /tmp/test:/tmp/other@server:0`
      --wait                                                           Wait for the server(s) to be ready before returning. Use '--timeout DURATION' to not wait forever. (default true)
Global Flags:
      --timestamps   Enable Log timestamps
      --trace        Enable super verbose output (trace logging)
      --verbose      Enable verbose output (debug logging)In our case we can simply say
k3d cluster create spinnakerINFO[0000] Prep: Network                                
INFO[0000] Created network 'k3d-spinnaker'            
INFO[0000] Created image volume k3d-spinnaker-images  
INFO[0000] Starting new tools node...                   
INFO[0000] Starting Node 'k3d-spinnaker-tools'        
INFO[0001] Creating node 'k3d-spinnaker-server-0'     
INFO[0001] Creating LoadBalancer 'k3d-spinnaker-serverlb' 
INFO[0001] Using the k3d-tools node to gather environment information 
INFO[0001] HostIP: using network gateway 172.20.0.1 address 
INFO[0001] Starting cluster 'spinnaker-1'               
INFO[0001] Starting servers...                          
INFO[0001] Starting Node 'k3d-spinnaker-server-0'     
INFO[0008] All agents already running.                  
INFO[0008] Starting helpers...                          
INFO[0008] Starting Node 'k3d-spinnaker-serverlb'     
INFO[0015] Injecting records for hostAliases (incl. host.k3d.internal) and for 2 network members into CoreDNS configmap... 
INFO[0017] Cluster 'spinnaker' created successfully!  
INFO[0017] You can now use it like this:                
kubectl cluster-infoEventually you will be able to list the cluster creation like below
> k3d cluster list     
NAME        SERVERS   AGENTS   LOADBALANCER
spinnaker   1/1       0/0      trueUse the newly created cluster
> kubectl config  get-contextsCURRENT   NAME                                                 CLUSTER                                              AUTHINFO                                             NAMESPACE   
          k3d-spinnaker                                        k3d-spinnaker                                        admin@k3d-spinnaker                                  spinnaker
*         k3d-spinnaker-1                                      k3d-spinnaker-1                                      admin@k3d-spinnaker-1                                
          rancher-desktop                                      rancher-desktop                                      rancher-desktop                        > k config use-context k3d-spinnaker
Switched to context "k3d-spinnaker".It is recommended to avoid default namespace so I will be using Namespace :
spinnaker
Step 2: devspace init
Init allows your configure as per your need and will generate devspace.yaml that will be eventually used for subsequent steps
devspace init -h#######################################################
#################### devspace init ####################
#######################################################
Initializes a new devspace project within the current
folder. Creates a devspace.yaml with all configuration.
#######################################################
Usage:
  devspace init [flags]
  
Flags:
      --context string      Context path to use for intialization
      --dockerfile string   Dockerfile to use for initialization (default "./Dockerfile")
  -h, --help                help for init
      --provider string     The cloud provider to use
  -r, --reconfigure         Change existing configuration
  
Global Flags:
      --config string                The devspace config file to use
      --debug                        Prints the stack trace if an error occurs
      --disable-profile-activation   If true will ignore all profile activations
      --inactivity-timeout int       Minutes the current user is inactive (no mouse or keyboard interaction) until DevSpace will exit automatically. 0 to disable. Only supported on windows and mac operating systems (default 180)
      --kube-context string          The kubernetes context to use
  -n, --namespace string             The kubernetes namespace to use
      --no-warn                      If true does not show any warning when deploying into a different namespace or kube-context than before
  -p, --profile strings              The DevSpace profiles to apply. Multiple profiles are applied in the order they are specified
      --profile-parent strings       One or more profiles that should be applied before the specified profile (e.g. devspace dev --profile-parent=base1 --profile-parent=base2 --profile=my-profile)
      --profile-refresh              If true will pull and re-download profile parent sources
      --restore-vars                 If true will restore the variables from kubernetes before loading the config
      --save-vars                    If true will save the variables to kubernetes after loading the config
      --silent                       Run in silent mode and prevents any devspace log output except panics & fatals
  -s, --switch-context               DEPRECATED: Switches and uses the last kube context and namespace that was used to deploy the DevSpace project
      --var strings                  Variables to override during execution (e.g. --var=MYVAR=MYVALUE)
      --vars-secret string           The secret to restore/save the variables from/to, if --restore-vars or --save-vars is enabled (default "devspace-vars")For my spinnaker-hellow app, I chose the following values
devspace init --debug             
     ____              ____                       
    |  _ \  _____   __/ ___| _ __   __ _  ___ ___ 
    | | | |/ _ \ \ / /\___ \| '_ \ / _` |/ __/ _ \
    | |_| |  __/\ V /  ___) | |_) | (_| | (_|  __/
    |____/ \___| \_/  |____/| .__/ \__,_|\___\___|
                            |_|
? How do you want to deploy this project? helm: Use my own Helm chart (e.g. local via ./chart/ or any remote chart)
? Which Helm chart do you want to use? 
? Please enter the relative path to your local Helm chart (e.g. ./chart) hellow
? What is the main container image of this project which is deployed by this Helm chart? (e.g. ecr.io/project/image) bhanuni/spinnaker-hellow
? How should DevSpace build the container image for this project? Based on this existing Dockerfile: ./Dockerfile
19:10:41 [info]   DevSpace does *not* require pushing your images to a registry but let's check your registry credentials for this image (optional)
[wait] ⠇ Checking registry authentication for hub.docker.com (25s)
                                                                       
19:11:08 [warn]   Unable to find registry credentials for hub.docker.com
19:11:08 [warn]   Running `docker login` for you to authenticate with the registry (optional)
? What is your username for hub.docker.com? (optional, Enter to skip) 
19:11:08 [warn]   Skipping image registry authentication.
19:11:08 [warn]   You may ignore this warning. Pushing images to a registry is *not* required.
? Which port is your application listening on? (Enter to skip) 8181
19:11:44 [info]   Configuration saved in devspace.yaml - you can make adjustments as needed
19:11:44 [done] √ Project successfully initialized
         [info]   
You can now run:
- `devspace use namespace` to pick which Kubernetes namespace to work in
- `devspace dev` to start developing your project in Kubernetes
- `devspace deploy -p production` to deploy your project to Kubernetes
- `devspace -h` to get a list of available commandsThis will generate a devspace.yaml file which we will edit for custom values.
I have configured a secret docker-registry
samarthya-dockerfor the credentials for the docker hub.
> k get secrets
NAME                  TYPE                                  DATA   AGE
samarthya-docker      kubernetes.io/dockerconfigjson        1      3h11mEdit the devspace.yaml for the secrets
pullSecrets:
- registry: "samarthya-docker"
  username: ${REGISTRY_USERNAME}
  password: ${REGISTRY_PASSWORD}Use Namespace: Spinnaker
> devspace use namespace spinnaker
[done] √ Successfully set default namespace to 'spinnaker'Configure the Values.yaml to override
deployments:
    values:
      image:
        repository: ${IMAGE}
        tag: "189"Step 3: devspace deploy
devspace deploy [info]   Using namespace 'spinnaker'
[info]   Using kube context 'k3d-spinnaker'
[info]   Skipping deployment spinnaker-hellow                                
[done] √ Successfully deployed!
         
Run: 
- `devspace open` to create an ingress for the app and open it in the browser 
- `devspace enter` to open a shell into the container 
- `devspace logs` to show the container logs
- `devspace analyze` to analyze the space for potential issuesStep 4: devspace open
Issue the open command to view the application

Look at the namespace used and the context used
[info]   Using namespace 'spinnaker'
[info]   Using kube context 'k3d-spinnaker'Browse and check the two end points '/ping' and the ‘/'


devspace list deployments
[info]   Using namespace 'spinnaker'
[info]   Using kube context 'k3d-spinnaker'
 NAME               TYPE   DEPLOY   STATUS        
 spinnaker-hellow   Helm   hellow   Status:Deployed Once the helm deployment has been success you can even check the service deployment via CURL
> devspace deploy
[info]   Using namespace 'spinnaker'
[info]   Using kube context 'k3d-spinnaker'
[info]   Execute 'helm upgrade spinnaker-hellow --namespace spinnaker --values /var/folders/p5/rfwqvcnj1zz9k3vxwq0vf9br0000gp/T/2512541306 --install hellow --kube-context k3d-spinnaker'
[done] √ Deployed helm chart (Release revision: 1)                     
[done] √ Successfully deployed spinnaker-hellow with helm              
[done] √ Successfully deployed!
         
Run: 
- `devspace open` to create an ingress for the app and open it in the browser 
- `devspace enter` to open a shell into the container 
- `devspace logs` to show the container logs
- `devspace analyze` to analyze the space for potential issuesGet Service
> k get svc
NAME                                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                     AGE
haproxy-kubernetes-ingress-default-backend   ClusterIP   None            <none>        8080/TCP                                    16h
haproxy-kubernetes-ingress                   NodePort    10.43.114.107   <none>        80:31622/TCP,443:32274/TCP,1024:31072/TCP   16h
spinnaker-hellow                             ClusterIP   10.43.153.162   <none>        8181/TCP                                    5sRun the curl command from the cluster
/bin # curl http://10.43.153.162:8181/ping
{"Status":"OK"}
/bin # curl http://10.43.153.162:8181/
Hello, Docker! <3/bin # Check logs: devspace logs
> devspace logs
? Select a container spinnaker-hellow-657fc75c65-n4hrg:hellow
[info]   Printing logs of pod:container spinnaker-hellow-657fc75c65-n4hrg:hellow
2022/02/16 07:06:42  initializing the application FN:init 
   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.6.3
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8181
{"time":"2022-02-16T07:06:58.638811863Z","id":"","remote_ip":"10.42.0.55","host":"10.43.153.162:8181","method":"GET","uri":"/","user_agent":"curl/7.80.0","status":200,"error":"","latency":18000,"latency_human":"18µs","bytes_in":0,"bytes_out":17}
{"time":"2022-02-16T07:07:01.311488863Z","id":"","remote_ip":"10.42.0.55","host":"10.43.153.162:8181","method":"GET","uri":"/ping","user_agent":"curl/7.80.0","status":200,"error":"","latency":180000,"latency_human":"180µs","bytes_in":0,"bytes_out":16}
{"time":"2022-02-16T07:09:18.921986863Z","id":"","remote_ip":"10.42.0.55","host":"10.43.153.162:8181","method":"GET","uri":"/","user_agent":"curl/7.80.0","status":200,"error":"","latency":212000,"latency_human":"212µs","bytes_in":0,"bytes_out":17}In the next blog I will try and configure it via ingress
