HomeVideos

Deploying NodeJS & Nginx to Kubernetes using Helm Charts

Now Playing

Deploying NodeJS & Nginx to Kubernetes using Helm Charts

Transcript

2144 segments

0:00

quick guide on taking a nodejs and nginx

0:03

application

0:04

and deploying it on a kubernetes cluster

0:06

using hand charts

0:08

to quickly talk about the app that we'll

0:09

be working on today

0:12

it is a repository that has two node.js

0:15

applications app and user service

0:18

app is an is a node server

0:21

that runs on port 3000 it has a couple

0:25

of endpoints

0:26

one is a health check endpoint called

0:27

slash ping

0:29

there's another end point that is on the

0:31

root which

0:33

returns a html page

0:36

and another endpoint that actually

0:39

proxies to another service which is on

0:40

slash api

0:41

users which if you can see here hits low

0:44

close 4000

0:46

um on a different endpoint and return

0:48

takes the data and returns it back to

0:49

the client

0:52

and the server that runs on port 4000 is

0:54

a user service

0:55

so the user service is again a node.js

0:57

application it runs a port 4000

1:00

it has a single endpoint called slash v1

1:02

users

1:03

which has a mocked set of users for this

1:06

example

1:07

and returns those users back to whoever

1:10

is consuming it which in this case is

1:11

app

1:12

and just to throw in another layer

1:16

into the mix there is an nginx

1:19

uh server that also has to run alongside

1:21

these

1:22

not a local developer development

1:24

environment but we say this is being

1:26

deployed to maybe

1:28

a production environment we would want

1:30

nginx to sit in front of our localhost

1:32

3000

1:32

server to essentially allow accesses

1:36

on port 80 and forward those along to

1:40

port 3000

1:41

so that is a little bit easier for

1:42

people to access our server

1:44

and just as a quick optimization

1:47

there is an error page that's rendered

1:49

which for any

1:50

five xx errors it returns this a

1:54

maintenance.html uh page

1:58

which just says that the site is down

1:59

for maintenance so to see this app in

2:02

action

2:02

locally uh we are exposing

2:06

a start command through the package json

2:08

called start all

2:09

which internally runs the start app and

2:12

the start user service

2:14

scripts which run the app and user

2:16

service respectively

2:18

so now let's just jump back to the

2:20

terminal and

2:22

start both of the apps

2:25

and you can see that the user service is

2:27

running on port 4000 and the server is

2:29

running on port 3000

2:31

now we can jump to the browser

2:35

we can hit localhost 3000 and we can see

2:38

the

2:39

root handler returning the the static

2:42

text that we were sending back from the

2:44

handler

2:44

we can also hit the health check

2:45

endpoint and we can see that that works

2:47

as well

2:48

and we can hit api slash users

2:51

which takes a call to localhost 3000

2:55

makes another network called localhost

2:57

4000 which is the

2:58

user service server and returns the set

3:01

off and basically process proxy is the

3:03

set of users from

3:04

the user service back to the browser

3:08

and we can see that here the user

3:09

service was called and then the app

3:11

server returned the

3:12

slash api slash users call

3:17

now that we have an application that

3:18

runs locally let's see what we need to

3:20

do

3:21

now to take it from here and make all of

3:24

this run

3:25

as we've seen right now in a kubernetes

3:27

cluster

3:29

so we don't have a production

3:30

environment to test out

3:32

all of our kubernetes deployments but we

3:34

do have the means to set up one locally

3:37

so there are a couple of tools that need

3:39

to be set up to first

3:40

talk to kubernetes and to also set up a

3:42

local kubernetes cluster

3:44

the tools are all available on the

3:47

kubernetes documentation page but the

3:49

two things that we'll probably need

3:50

today are cube ctl which is a cli tool

3:54

that allows you to

3:55

plug into a kubernetes cluster to you

3:58

know

3:59

execute commands on the cluster and the

4:01

other one is mini cube

4:03

which allows you to spin up an entire

4:06

kubernetes cluster locally

4:08

and specifically for the demo today

4:13

we'll be using the docker desktops

4:16

kubernetes

4:17

uh capabilities so another tool that

4:20

will probably be

4:21

needed today is to install the actual

4:23

desktop uh

4:24

version of docker not just the cli

4:27

you should be able to verify if they've

4:29

been installed correctly

4:30

by running running a version on all of

4:33

them

4:34

so i have mini cube up cube ctl

4:37

up and docker up as well

4:41

but before we go into deploying

4:42

something to kubernetes

4:44

the question still remains on how do we

4:47

get something that is compatible with

4:48

keyboard with kubernetes right

4:50

and that's a prerequisite that we'll

4:53

have to sort of address

4:54

now which is we need to run all of these

4:58

applications that we have which are the

4:59

app server the user service

5:02

as well as nginx in docker environments

5:06

which essentially means that we have to

5:07

create docker images of images from them

5:10

and use those images to run containers

5:13

so that it's compatible in a kubernetes

5:14

environment

5:15

so to dockerize our application we need

5:18

to start by creating a docker file

5:20

and we if you really think about it we

5:22

have three different applications here

5:24

our app server our user service server

5:27

as well as nginx

5:28

which all have to be dockerized you by

5:30

creating docker files for them or

5:32

creating docker images using the

5:33

dockerfile configured for them

5:35

so let's let's first dockerize app here

5:38

so we can create a

5:39

file called dockerfile under it and

5:43

most if not all docker images start off

5:46

with a base docker image so for example

5:48

here

5:48

i need a linux environment and we also

5:51

need node to be running in the linux

5:53

environment so here i'm just saying that

5:55

use this version of alpine linux and

5:58

also have

5:59

this version of node available right so

6:01

that's the tag that i'm using here

6:04

now our docker image needs to

6:07

essentially have three things right uh

6:10

or rather the docker file has to have

6:11

three things

6:12

one is how to like what code do we need

6:15

to move from our host system

6:16

into the docker image what port to

6:19

exposed

6:20

because networking is sandbox to the

6:23

running container and your host system

6:24

so how do you interface between the two

6:26

of them

6:26

is by exposing ports so which port to

6:29

expose and finally what is the

6:32

final execution that needs to run when

6:35

the image is converted to a running

6:37

container

6:38

right so to move files from a host

6:40

system to the docker image let's first

6:42

create a working directory

6:44

so here let's create user

6:47

share app so once you run the working

6:50

directory command you

6:51

automatically create the directory and

6:53

cd into it so everything else that i do

6:54

after this is going to be

6:56

in uh like with respect to that user

6:58

share

6:59

app directory so the first thing we need

7:01

to copy is our server code

7:03

which is going to be available in app

7:05

server.js and we'll move it to

7:07

our file called server.js inside this

7:09

working directory

7:11

now to make this server.js actually work

7:14

we need the node modules to be

7:16

available so that all of our install

7:18

packages are actually available on that

7:19

image as well

7:20

so let's copy node modules

7:24

as well now we know that the app server

7:27

ex like runs on port 3000 right so we

7:30

need a way to talk to this localhost

7:32

3000

7:33

server and that can be done by exposing

7:36

the 3000 port

7:38

which allows anyone who's using this

7:40

image to be able to

7:41

map a host port to the exposed port by

7:45

the docker image thereby allowing us to

7:47

directly talk to the server when it's

7:48

running on port 3000

7:51

and the last thing is to have the final

7:54

command that needs to run when you

7:55

convert this image to a running

7:57

container so

7:58

everything above this is at build time

8:00

so we build the image and keep it ready

8:02

but every time we spin up a container

8:04

from that image we actually execute

8:06

what's

8:06

what's been provided here in the cmd

8:10

statement now cmd is just an array of

8:13

strings

8:13

uh each part of the of the array is

8:17

going to be

8:17

one space separated entity so here we

8:20

want to run the server so we say node

8:23

server.js all right

8:26

and this is pretty much all that we need

8:27

to do to dockerize

8:29

our app uh our app server and have it

8:33

running and exposing the

8:34

3000 port so so let's also tweak this

8:37

and copy it over to the

8:38

nginx server and the user service server

8:40

to dockerize those servers as well

8:55

[Music]

9:04

so now we have dockerfiles available for

9:08

our app server

9:09

our nginx server as well as our user

9:11

service the only tweaks that were made

9:13

were

9:13

in user service we copied over the the

9:16

user services

9:17

node server and we exposed 4000 instead

9:20

of 3000 and in the case of nginx we have

9:23

a different

9:24

base image we copied the default conf to

9:27

the necessary configuration

9:29

route for nginx and we've also copied

9:32

our maintenance html to another

9:34

folder that's relevant to nginx on that

9:36

image we've exposed port 80 because

9:38

nginx runs on port 80

9:40

and we are also saying that the nginx

9:42

should not run as a daemon

9:43

this is kind of important here because

9:47

a container will stop running when the

9:50

when this command ends right so if this

9:53

reaches reaches a conclusion

9:55

then you then docker things that your

9:58

container has essentially

9:59

uh stopped right uh nginx when it when

10:02

when you

10:03

when you run nginx it runs as a daemon

10:05

by default which means that

10:06

the command to start nginx would start

10:09

and stop almost immediately

10:11

so what we're just saying here is to

10:12

turn off the daemon mode

10:14

so that the the process that starts

10:16

nginx is also the process that's

10:18

actually running nginx as well so now

10:21

that we have docker files available for

10:23

all three of our applications

10:24

let's use the dockerfile to generate

10:26

docker images

10:28

for each of these applications and spin

10:30

them up locally as containers just to

10:32

see if you've dockerized everything

10:33

correctly

10:34

so to create a docker image using a

10:37

docker file you use the docker build

10:38

command

10:39

you can give it a context so in this

10:41

case we're giving the current

10:43

like folder as a context but the fact

10:45

that but the

10:47

like the fact that we have three docker

10:49

files means that we

10:50

like we can't let docker know which of

10:52

these dockerfiles are relevant for

10:53

certain

10:54

um like image build statements so that

10:57

can be done using a minus f

10:59

argument which allows you to selectively

11:00

say that this is the file i want to use

11:03

so in our case we want to let's say we

11:05

want to run the

11:06

build command for the app server first

11:09

so we can pass an app

11:10

docker file and we can pass in the minus

11:12

t argument to

11:14

now provide a name to this image so

11:18

the image is going to be called app

11:19

server and the tag for this image is v1

11:22

right and tag is just a way for you to

11:24

have multiple versions of the same

11:26

image so now we run this we can see that

11:30

a bunch of steps have run each of these

11:31

steps are the steps that are available

11:33

in our docker file for instance

11:35

and now when we run docker images we can

11:38

see that the app server is available

11:40

uh with the tag v1

11:43

now let's quickly spin up this docker

11:46

image into uh

11:48

into a running docker container to

11:50

actually see if our app server is up and

11:51

running correctly

11:53

so to to run an image that has already

11:56

been built you can use the docker run

11:58

command

12:00

you can pass in the minus d flag to

12:03

ensure that you

12:04

you don't like use the same terminal

12:06

session for

12:08

like viewing the logs for that docker

12:10

image so you basically detach it and

12:11

let it run behind the scenes um then you

12:14

can pass in the minus p

12:15

flag to map a host port to the port that

12:18

has been exposed by the docker image

12:20

so for example here i want my 3000 port

12:22

my 3000 port to be mapped to the 3000

12:24

port exposed by

12:26

the docker image and finally we can pass

12:28

in the

12:29

image name which in this case is app

12:31

server

12:32

and the tag is v1 right so the moment we

12:36

run this we get a sha

12:38

and we can check the logs for this show

12:41

by

12:42

by just running docker logs on it and we

12:44

can see that the server is currently

12:45

running on port 3000

12:48

so test this out let's jump back to the

12:50

browser

12:51

and we already had this running for

12:53

instance right here

12:54

so i can hit the health check endpoint

12:56

and we can see that the server is still

12:58

running on port 3000

12:59

and this uh response is actually coming

13:02

in coming from the server running inside

13:05

our docker container and not the server

13:07

that's running on a local system

13:09

which we actually killed fairly early on

13:12

so cool so the app server is running so

13:14

let's do the same exercise with

13:16

the with the user service service

13:20

as well as the docker uh the nginx

13:22

service as well

13:24

so we can run the build command again

13:26

except now instead of passing the docker

13:28

file for

13:29

app we pass in the docker file for user

13:31

service

13:33

and the name for this is going to be

13:34

user service

13:36

v1 is again the tag for it we can see

13:39

that this runs as well

13:40

it's been tagged now let's run

13:43

the user service

13:46

image and we know that this wants to run

13:49

on port 4000

13:50

and just to show that the host port and

13:52

the expose port don't necessarily have

13:54

to be the same let me run this on

13:56

5000 on my local system but map it to

13:58

the 4000 exposed by the

14:00

docker image so we can see that this

14:04

again has spit out a sha which means

14:07

that the run command actually

14:08

ran successfully and we can see that

14:12

it is running on port 4000 so when i

14:14

jump back here

14:16

i can go to localhost 4000 slash

14:19

v1 slash users but this doesn't work

14:22

because we mapped 5000 from our host

14:25

system to the 4000 that's available on

14:27

the image

14:27

so let's hit 5000 rather on our

14:32

on our host system and we can see that

14:33

the response comes back with the mock

14:35

users

14:36

so user service is also working so let

14:39

the last test is going to be for nginx

14:41

so let's build the

14:45

nginx image and call it app engine xv1

14:49

uh mostly because nginx is like a

14:52

an existing docker hub image name

14:56

so this runs as well docker

15:00

run and let's have this

15:03

port 80 little map to 80 as well

15:07

and this is going to run app engine x

15:11

now let's see docker logs for this uh

15:14

and we can see that

15:14

the everything is up and running now we

15:17

really can't test

15:18

proxy passes right now because none of

15:20

these images know about each other

15:21

but one thing that we can test is if the

15:24

maintenance page is rendered

15:25

so let me maintenance

15:28

dot html and we can see that ah the

15:32

maintenance page that we configured in

15:34

our nginx container

15:35

uh sorry in our nginx server is now

15:39

being rendered because we directly hit

15:41

maintenance or html

15:43

so as it stands now we have three images

15:46

one for our app server one for our user

15:49

server and our nginx server and all of

15:51

these

15:51

are up and running on our local system

15:53

and we've tested all of these and

15:55

everything seems to be going absolutely

15:56

fine

15:58

so now that we tested all of our docker

16:00

images

16:02

by running containers locally and

16:04

verifying that things are working fine

16:06

let's now move on to the kubernetes side

16:08

of things

16:09

so we did initially install a bunch of

16:12

tools

16:13

such as cube ctl and mini cube to be

16:15

able to run

16:16

a local kubernetes cluster but we just

16:19

did the installation we didn't actually

16:21

spin up the cluster

16:22

so we can run the mini cube start

16:24

command

16:25

to spin up this cluster and as i

16:28

mentioned earlier

16:29

we also want to use the docker's

16:32

kubernetes capabilities

16:33

and not uh running on a different

16:36

virtual machine within the system so we

16:38

can pass in the driver as docker here

16:40

so once we hit the start command a bunch

16:43

of commands

16:43

uh execute and minicube essentially

16:46

spins up this cluster which should take

16:48

some time

16:50

maybe about a minute or so

16:52

[Music]

17:02

cool now that now that mini cube has

17:05

spun up and there's a running cluster at

17:08

this point in time we can actually

17:09

verify this by opening the docker

17:11

desktop again

17:12

and we can see that the that mini cube

17:15

is now controlling a cluster

17:16

in in in docker's constant context

17:20

uh so mini cube come not just minicube

17:23

rather but like kubernetes

17:25

installations usually come with a

17:27

dashboard that lets you see

17:29

what is running in your cluster and

17:33

what are the different entities that are

17:35

currently

17:36

running and what this what the status of

17:37

those entities are so we can run

17:39

mini cube dashboard which

17:42

tunnels and exposes the dashboard

17:44

capabilities of the kubernetes

17:46

installation to your local system so

17:49

the moment we run a mini cube dashboard

17:51

we can see that

17:53

kubernetes is running and this is the

17:56

default

17:57

set of configuration for it but we can

18:00

also see that there are

18:01

there's nothing else that's running

18:02

apart from just kubernetes as

18:04

is and that's where everything that we

18:07

did before this which is around creating

18:09

docker images plays part so

18:14

as part of the guide today this is

18:17

sort of what we want to recreate right

18:20

we want to create a cluster that

18:23

runs an nginx server which sits in front

18:26

of three app servers

18:29

which again works on top of two user

18:32

services right

18:34

and the three and two are just like

18:37

just numbers that are being used for

18:39

this demo but technically this could be

18:41

scaled up or scaled down based on

18:42

whatever load that you see fit

18:44

and if you notice in front of all of

18:47

these

18:48

three apps we have services that are

18:52

running

18:53

and what load balancer and cluster ipr

18:55

is something that i'll get to in a bit

18:57

uh but we have the way have the means of

18:59

referring to a single entity

19:01

who under the hood points to the

19:03

individual running

19:06

versions of the app so for example here

19:09

all of these apps talk to a single

19:11

service who then

19:13

load balances between the two users

19:15

running user service instances

19:17

and nginx talks to a single service

19:19

which under the hood

19:20

load balances between multiple apps so

19:22

this is the entire cluster that we are

19:24

going to

19:25

bring into our kubernetes installation

19:28

locally

19:29

and at this point in time we have the

19:31

images available

19:33

for all of these but how do we go about

19:35

creating this cluster

19:37

and that's where something called

19:38

resource manifests play a part

19:40

to talk about what these resource

19:42

manifests are we need to step

19:44

take a step back and talk about what

19:46

pods are so

19:48

pods are the most atomic entity that can

19:51

be deployed to a cluster

19:52

and what a pod essentially is is a

19:54

running instance of your application

19:57

so containers are also running instance

20:00

of your application so what's the

20:01

difference right

20:02

so a pod in most cases would

20:06

be just the container that you're

20:07

running right so the same container that

20:09

we had for our app server user service

20:11

and nginx

20:12

uh is just for all intents and purposes

20:15

called a pod in the kubernetes and

20:18

like world but the definition

20:22

truly means a running instance of your

20:23

application right so if you have a

20:25

if you have multiple closely coupled

20:27

containers

20:28

uh which have to really work with each

20:30

other to to

20:32

to function right maybe you have like a

20:34

like a like a node.js server that's

20:35

sitting on top of a database for

20:37

instance

20:37

in cases like this you would want these

20:40

containers to coexist at all

20:42

times and that's when a pod in this case

20:44

could potentially have multiple

20:45

containers under them

20:46

so again the the definition is a running

20:49

instance of your app

20:50

whether it's one container which is what

20:52

is going to be in most cases

20:53

or multiple containers is on a

20:55

case-by-case basis

20:57

so here nginx each of these app

20:59

instances and each of the user service

21:02

instances are all pods

21:03

right so here if you want to create this

21:06

cluster we want one

21:07

part of nginx three pods of the app

21:10

server and two pods of user service

21:12

but then um it gets a little bit

21:16

uh manual to spin up pods one by one

21:20

right like we'll have to

21:21

uh run the pod creation command three

21:24

times to get the app server up and two

21:26

times to get the user service up

21:28

and if you want to scale them in the

21:29

future for maybe to support a much

21:31

larger workload

21:32

we have to keep applying them over and

21:34

over and over again so that's where the

21:36

first resource manifests that we'll be

21:38

working with today comes into play

21:39

which is called a deployment so a

21:42

deployment is basically

21:44

a declarative way to work on pods

21:48

so what i could essentially say here

21:50

through a simple yaml file

21:52

is that i want this pod to have this

21:56

container and i want these many

21:57

instances of that

21:59

of that pod available in my cluster

22:01

right and i can also provide

22:03

metadata to these pods to uh

22:06

make other pods and services in my

22:09

cluster

22:10

understand these pods right and it's all

22:12

done through a single dml file

22:14

now the second type of resource that

22:16

we'll probably be talking about today

22:18

is these um these service

22:21

type resource resources so

22:25

a service essentially sits in front of a

22:28

number of pods

22:29

and acts as a proxy mechanism between

22:33

uh people who want to access these pods

22:35

and the number of pods behind it

22:37

so i can scale up these pods uh

22:40

for to handle a larger workload or scale

22:43

it down

22:43

and i don't have to care about the

22:45

individual ips of these but rather i

22:47

would

22:47

reference a single service and that

22:49

service would under the hood

22:51

talk to these these pods so if if let's

22:54

say one of these pods gets removed for

22:56

another pod

22:57

it doesn't matter the service still

22:58

knows about the service is still the

23:00

abstraction that everyone else talks to

23:03

now

23:04

uh there are two types of services that

23:05

this cluster has in this

23:07

in this example one is a load balancer

23:09

service and the other one's a cluster ip

23:10

service

23:11

right so the the stark difference

23:13

between the two

23:14

is cluster ip services are only

23:18

recognized by other pods and services

23:20

running inside the cluster

23:22

whereas a load balancer service as you

23:24

can see here is something that exposes

23:26

an endpoint that the rest of the world

23:29

can request to

23:30

so uh any requests that are outside the

23:33

cluster can only come through a load

23:34

balancer not through a cluster

23:36

ip because this is only relevant within

23:38

the cluster and not exposed to the

23:39

external world

23:41

so in our example we don't want our app

23:43

server to be exposed directly we don't

23:45

want our user service to be exposed

23:46

directly

23:47

we want all requests to come through

23:49

nginx maybe we have some

23:50

like like some authorization that runs

23:52

here or maybe we have some sort of a

23:55

pre-sanity or something of that sort

23:56

right so we can do all of that here and

23:59

we can

24:00

ensure that all of the requests are

24:01

funneled through a single mechanism

24:03

through this load balancer service

24:06

now i mentioned that all of these are

24:09

resource manifests that control these

24:11

these different resources

24:12

and i did mention that all of these are

24:14

yaml files right so

24:16

let's just create a quick uh resource

24:19

manifest that controls our

24:21

app pods to begin with

24:25

so to actually see one of these resource

24:27

manifests in action

24:28

let's jump back to our code base so uh

24:31

we want to create a deployment resource

24:32

for app

24:33

where which specifies what container i

24:35

want to run and how many instances of

24:37

the container i want to run right

24:39

so under app i can create a file let's

24:41

call it deployment

24:43

dot yaml and

24:47

in this deployment.dml i'm going to

24:49

specify my configuration for this

24:51

deployment resource

24:52

so the the first key is something that's

24:55

pre-configured by kubernetes it's

24:57

standard across

24:58

all deployment resources which is this

25:01

api version

25:02

we are also going to say that the kind

25:04

is deployment which means that this yaml

25:06

is going to be specifically to talk

25:08

about our deployment resource

25:11

now we can also provide some metadata

25:13

and like i said uh

25:14

these resource manifests allow you to

25:16

provide uh metadata that

25:18

for other resource manifests to to uh

25:21

like link to so here i'm providing in

25:24

metadata

25:25

calling this this deployment resource

25:28

and app server deployment

25:30

right and uh now comes in the main part

25:33

which is the specification for this

25:35

for this deployment resource so under

25:37

the spec key i can specify how many

25:39

replicas i want of

25:41

something right now what this something

25:44

is is based on a selector

25:46

so i can say that whatever is matching

25:49

a set of labels whose name

25:52

or whose key is server and value is

25:55

let's call it app server right

25:56

and what you provide under match labels

25:58

is is irrelevant

26:00

uh you can have any key and any value is

26:03

just that you need to match this to

26:04

something that

26:05

you have specified in your in your

26:09

container spec which is what we'll be

26:10

building next so now

26:12

we're just saying that whatever matches

26:14

this label server app server

26:16

spin up three replicas of that right so

26:19

we can create a template for

26:21

our our deployment and we can provide

26:24

metadata to this

26:25

one such key is labels and into the

26:28

labels i'm going to provide server app

26:30

server

26:30

so this is how this piece of

26:33

the replica count is actually tying into

26:37

uh the template for the

26:40

pods so now that we've provided metadata

26:43

we need to actually provide the spec

26:44

for the pods so the specs here is going

26:47

to be the

26:48

the containers that we want to run as

26:49

part of this this pod

26:51

so we we can have an array called

26:53

containers here so

26:55

the container name can be anything

26:57

doesn't really matter uh it's just for

26:59

uh like denoting or the or rather this

27:03

is the name that will show up in your

27:04

kubernetes dashboard

27:06

so we have the name the image is what's

27:09

important which is what

27:10

is the image for the container that we

27:11

want to run right so in our case we know

27:13

that is app server v1

27:15

all right and since we want to run a

27:18

local kubernetes cluster

27:20

we don't want our images to be pulled

27:22

from docker hub which is what the

27:25

the default lookup for a kubernetes

27:27

cluster is

27:28

so since we have our images only

27:30

available on local i'm going to be

27:31

putting an image pull

27:32

policy for this as never which means

27:34

that never look it up

27:36

always use the images that are available

27:38

but based on your use case you can

27:40

if you're using something that's already

27:41

available on docker hub you could

27:43

omit this or if you're using something

27:46

from a custom registry again you will

27:47

have to probably omit this

27:49

then uh the next part is ports so our

27:52

containers are our container is going to

27:54

expose ports

27:55

so we can provide a container

28:00

container port

28:03

so in this case this is again an array

28:05

of values because a container can expose

28:07

multiple ports but

28:08

in our case it's just exposing a single

28:11

port which

28:12

is a port 3000 right and here is where

28:15

you can also provide

28:16

other additional env variables so uh

28:19

just for the time being let's just pass

28:20

in env

28:21

variables just just to test this out so

28:24

we can pass in

28:25

an array of env variables where uh the

28:27

you can provide a name for the env

28:29

variable let's say no dnv

28:31

and the value is going to be let's say

28:34

production

28:34

right so this is

28:38

uh how a deployment resource manifest

28:41

looks

28:41

where we just say that the kind is

28:43

deployment here's some metadata about

28:44

the deployment itself

28:46

and the specification for it where i say

28:48

that for whatever

28:51

spec matches this label right

28:54

uh spin up three replicas of it and

28:57

i've also specified that this is what

28:59

the label is going to be which is server

29:00

app server which is how these two tie in

29:02

and here's my spec which defines what

29:04

the containers are going to be inside

29:06

this template

29:07

where i say that my container is going

29:09

to be this image and this is the port

29:11

that i want to expose and these are the

29:12

env variables for my container

29:14

right so now let's actually apply this

29:17

deployment to a kubernetes cluster and

29:18

see

29:19

if at least this part of my

29:23

cluster is spun up correctly right

29:26

so to apply certain uh

29:30

resource manifests you can use cubectl

29:32

which is again something that we

29:33

installed early on so the cubectl

29:36

command here

29:37

is now directly talking to the

29:39

kubernetes

29:40

cluster that's running inside our docker

29:43

context

29:45

so cube ctl takes a bunch of commands

29:47

here we want to apply a new resource so

29:49

we use the apply command

29:50

we apply a file which is what the minus

29:52

f stands for and

29:54

we want to apply the app slash

29:56

deployment.yaml

29:58

right and this is going to take a while

30:01

to run

30:01

and we can see that uh there is an error

30:04

and that's because ds dns names need to

30:07

have

30:10

lowercase alphanumeric values so let's

30:13

change this to deployment

30:15

and let's run this again and we can see

30:17

that the deployment has been created

30:19

so now we can open up that

30:23

that dashboard that we had right using a

30:26

mini cube dashboard and it will open

30:28

this up and we can see that

30:31

there are three parts that spun up and

30:34

uh the container image is not

30:37

present is is the error that's that's

30:40

showing up here right

30:41

and that's interesting because we did

30:42

build it uh locally and we said that

30:44

don't pull it from anywhere right so why

30:46

can't it look further

30:47

or rather why can't it find this image

30:50

from our local system

30:51

and that's kind of where and this

30:53

wouldn't make sense wouldn't be

30:55

uh something that will show up in uh

30:57

maybe a production environment but at

30:59

least for

31:00

building locally there are some certain

31:02

things that we need to do to get

31:03

get our mini cube talking to our local

31:07

docker

31:07

environment what i mean by that is if i

31:09

do docker images right

31:12

i can see that these images are

31:14

available locally

31:16

but these images are actually not

31:17

available inside mini cube

31:19

which is what's controlling the

31:20

kubernetes cluster there

31:22

so if i if let's say i run this command

31:26

which

31:27

uses the mini cube's docker environment

31:29

and i run docker images

31:32

i can see that my images are not

31:34

available in the context of the docker

31:37

daemon running inside mini cube and mini

31:40

cube can only

31:41

like pull up images that are within its

31:43

docker environment right

31:44

so now we'll have to probably now that

31:47

we've run this eval command we

31:49

are now connecting our dock or rather

31:51

using minicube's docker daemon on our

31:53

on our host system and now we need to

31:56

rebuild these images

31:57

on that docker context to ensure the

32:00

mini cube is able to see this again this

32:02

is not something that you would run into

32:04

in a production environment

32:05

but for mini cube this is a small little

32:07

thing that we need to do

32:08

so let's run those docker build commands

32:10

again so

32:11

let's build app nginx v1

32:15

so it's going to uh like pull in

32:17

everything and

32:18

uh like start from scratch again

32:22

so if you can see here it spun

32:24

everything up from scratch and now if i

32:25

run docker images

32:27

i can see that app engine x is available

32:31

now let's also create the images

32:35

for user service

32:44

which again happens from scratch

32:52

and let's also build it

32:57

for our app server

33:01

right now when we run docker images we

33:04

can see that

33:05

our app server our user service as well

33:07

as our app engine x are all available

33:08

now inside mini cube

33:10

so let's jump back here and

33:15

you can either use the dashboard to like

33:16

check things or you can also use the

33:18

cube ctl command

33:19

to see what is running right now

33:23

so here for example i've gotten the pods

33:25

for instance

33:26

uh that are running inside my uh inside

33:28

my cluster and now you can see that the

33:30

pods are running

33:31

right and that's because we now have the

33:34

image available inside kubernetes

33:36

and because kubernetes is a self-healing

33:38

uh environment

33:40

which means that if anything errors out

33:41

it tries to bring it up uh up

33:43

like over and over again until uh until

33:46

it succeeds

33:47

so in the in the previous case we didn't

33:49

have the image available so it failed

33:50

but the moment we made the image

33:52

available it tried to restart it and

33:53

found the image and now it's running

33:55

successfully

33:56

right so uh

33:59

let's also uh maybe check the logs for

34:03

one of these running pods so i can do a

34:04

cube ctl

34:06

logs and the pod name and we can see

34:08

that the server is running on port 3000

34:10

but again these pods are running within

34:13

the

34:14

cluster which means that there's no way

34:16

for us to access these

34:17

these uh pods directly from the outside

34:20

world right so

34:21

but then we can see that there are

34:22

exactly three replicas running for for

34:24

this uh service so now like i said if

34:27

you if you have a how if you have a

34:28

larger workload and you want to scale

34:30

things up

34:30

we can come back to this deployment at

34:32

gamble and we can probably

34:34

change the replicas to four and

34:37

come back to our terminal and apply

34:40

the deployment again and we can see that

34:43

deployment

34:44

ran and now when we get pods we can see

34:47

that there are four

34:48

pods now running where the latest pod

34:50

has spun up only recently which is

34:52

around four seconds ago

34:54

so that's how we can declaratively scale

34:56

up and scale down

34:57

uh running instances of our application

34:59

through a single resource

35:02

manifest instead of having to spin them

35:03

up one by one right

35:06

so now that we have a deployment running

35:08

let's add a service

35:09

to abstract away the deployment or the

35:12

pods behind the deployment

35:13

from other services that are running in

35:15

the cluster so

35:17

our service is also another type of

35:18

resource manifest that you can add

35:21

so in if you jump back here to the

35:23

cluster we can see that

35:24

we want our apps to sit behind a cluster

35:26

ip service

35:28

so we can come back to the to the code

35:31

base

35:32

create a service dot yaml file

35:36

and this is going to be similar to how

35:39

we defined

35:40

the deployment uh manifest so this is

35:44

there's an api version however the api

35:46

version here is v1

35:47

for services um the kind is going to be

35:50

a service

35:51

so uh it was a deployment for a

35:54

deployment manifest and for service

35:56

manifest it's

35:56

a kind service similar to our deployment

35:59

manifest we can provide

36:00

metadata to the service manifest itself

36:03

so we can have metadata name

36:06

is app server cluster ip service

36:12

and yep there we go

36:15

and uh and all of these resource yaml

36:20

files have spec that defines what the

36:23

manifest is supposed to do so the spec

36:26

for a service is going to define what a

36:27

type is

36:29

so you can have either a load balancer

36:31

type or a cluster ip type since

36:33

since we want a cluster ip so we'll add

36:36

the type as cluster ip

36:37

and every cluster ip service has

36:41

requests that that come into it and

36:43

requests that go from it right

36:45

and that's what the port the ports key

36:49

defines so you can you can highlight

36:51

which port

36:53

you are going to expose to the external

36:55

world

36:56

so in this case my port is going to be

36:58

80

36:59

but requests that come in on port 80

37:02

need to be funneled to the actual pods

37:04

and each port is running on a certain

37:06

port right so in our case

37:08

the pods that were defined by this

37:10

deployment yaml are all running on port

37:13

3000 so we can have our target port

37:16

set to 3000 so what this means is

37:19

requests come to the service on port 80

37:22

but then get sent to whatever sitting

37:24

behind the service on port 3000

37:26

and now we need this service to

37:29

work on the pods defined by this

37:31

deployment right and that's again where

37:33

the metadata

37:34

that we define here in terms of the

37:36

selector comes into play

37:38

so if you see here we had a label called

37:39

server app server so

37:41

we will use that here

37:45

which means that i want this service

37:49

to sit in front of pods that are

37:51

controlled or have the label

37:53

server app server

37:56

so now let's apply

37:59

this manifest as well so apply minus f

38:06

app and service dot yammer

38:11

and we can see that the service has been

38:13

created now when you do a q

38:15

cube ctl get you can now get services

38:18

which is the resource type that we've

38:20

introduced into the system

38:21

so if we get a service we can see that

38:23

there is a app server cluster ip service

38:26

that is running on this cluster ip but

38:28

exposes no external ips which means that

38:30

again

38:30

it's an i it's an ip that people or pods

38:34

within the cluster can

38:35

reference but no one from outside the

38:37

cluster can make

38:38

uh calls to it and we can also see that

38:40

this is exposing

38:42

the at port as a tcp connection

38:46

and if we go back to

38:50

the kubernetes dashboard

38:54

we can also see that we have

38:57

the app server cluster ip service and we

39:00

can also see that

39:02

like if we click on this we can see that

39:05

this cluster ip service

39:07

is sitting in front of these app server

39:09

deployments

39:10

which are the pods so they are able to

39:13

talk to each other

39:14

because we've provided them or provided

39:16

the service the the right selector to

39:18

select

39:19

so now if it doesn't matter how many how

39:21

many pods

39:22

this scales up to or scales down to this

39:25

cluster ip service is still going to be

39:27

the abstraction that everyone talks to

39:29

they don't have to talk to the pods

39:30

directly so now that we have

39:34

our deployment that's orchestrating our

39:37

app server pods

39:38

and we have a service that's sitting in

39:39

front of the app server let's go ahead

39:42

and construct the

39:43

rest of this cluster so we need a

39:45

cluster ip for user service and a

39:47

deployment that has two replicas for the

39:49

user service port

39:51

and we have a deployment of nginx with

39:53

one replica and a load balancer service

39:54

that sits in front of it

39:56

so there's some amount of copy paste

39:58

that's going to happen here so let's

39:59

take this deployment yaml

40:01

and put it inside the user service as

40:02

well and

40:04

we can change the uh the deployment name

40:07

from this to user service deployment we

40:10

want two replicas behind it

40:11

the server is going to be called

40:14

user service and

40:18

the image is user service v1

40:21

and we know that the user service

40:23

exposes port 4000 not 3000 so let's

40:26

change that out as well

40:28

now we also need a service for this

40:32

user service so let's add that here as

40:35

well

40:35

and we change this to user service

40:39

cluster ip service

40:40

it's again a cluster ip type port 80

40:42

target port is 4000

40:44

and we want this to talk to any server

40:47

that

40:47

matches or any label whose key server

40:50

and values user service

40:52

which should match this key here so

40:55

let's apply the

40:56

the the deployment and service for the

40:59

user service as well

41:00

so cube ctl apply minus f

41:05

um user service deployment yammer

41:08

so we can see that the deployment has

41:10

been created let's also go ahead and add

41:12

the service yaml

41:13

so we can see that that's been created

41:15

as well so if you do a cube ctl get

41:17

pods now we can now see

41:20

that there are four instances of app

41:23

server here

41:24

but then now the two instances of user

41:26

service that

41:27

have also been spun up and they're

41:28

running as well so this is being

41:30

controlled by the

41:31

user service deployment yaml that we

41:32

added and let's also do a cube ctl get

41:35

services

41:37

and we can see that there is a user

41:40

service cluster ip service

41:42

which is also running on a certain

41:44

cluster ip

41:45

and to see if it's connected correctly

41:47

we can go to the mini cube dashboard

41:51

or rather the kubernetes dashboard

41:52

through mini cube and we can

41:54

see that the user service

41:58

cluster ip service is here we can click

42:00

on it and we can see that it's sitting

42:02

in front of both the pods defined by our

42:04

deployment

42:05

now let's do the same for nginx and see

42:07

if this whole thing works end-to-end

42:09

right so let's copy this deployment and

42:12

add it to our nginx

42:13

folder um it's going to be called the

42:16

app

42:17

or let's just call it the nginx

42:20

deployment

42:20

we want one replica of this the server

42:23

is going to be called nginx

42:25

the server label is nginx as well

42:28

the name of the container is nginx the

42:31

image is actually app engine x

42:33

since we had namespaced it again v1

42:36

and container port exposes 80 and then

42:39

no

42:39

environment variables for it so we can

42:41

exclude that

42:43

now let's put another service in front

42:44

of it and this is where things

42:46

may change a little bit so we'll call

42:49

this the nginx

42:50

load balancer service and the type here

42:53

is load balancer now

42:56

all right and it's going to receive a

42:59

request on port 80 and the target port

43:01

is the same as that as the exposed port

43:03

by the nginx container which is port 80

43:05

and the selector here is going to be

43:07

nginx right which should match

43:09

our server engine next thing here

43:14

so now that we have this let's spin this

43:15

up as well so we can do a cube ctl

43:18

apply minus f of nginx

43:22

deployment so now nginx is spun up

43:25

and we can do a cube ctl apply

43:28

minus f of the nginx

43:32

service.gamble all right so let's do a

43:35

cube ctrl get pods just to see if the

43:37

deployment went through

43:38

and we can see that one engine export is

43:40

up and running which is about 14 seconds

43:42

ago

43:43

and we can also see that we can also get

43:46

the services

43:48

and we can see that there is a nginx

43:50

load balancer service

43:52

which has a cluster ip and if you notice

43:55

here instead of having none

43:56

as the external ip we have a key here

43:58

called pending

44:00

and this in a production environment

44:02

would actually

44:03

resolve to an ip that you can hit but

44:06

since we have a local kubernetes cluster

44:08

uh we need to do some mapping through

44:11

mini cube to get this to work

44:13

but just note here that uh the external

44:16

ip is something that

44:17

nginx load balancer service will

44:18

potentially expose that we can now

44:20

consume from our host system directly

44:22

which you couldn't do with the other

44:23

cluster ib services for instance

44:26

get this nginx load balancer service

44:28

expose

44:29

an external ip we can use the mini cube

44:33

service and the service name so what

44:36

this will do

44:36

is it will try to like tunnel

44:40

this ip to the host system so that we

44:43

can access it directly

44:45

so we can hit this in we can see that

44:49

we can see that yep so we are somehow

44:52

able to consume the

44:54

the internal ip here

44:57

right but if you notice the moment we go

45:00

there it says that the site is done for

45:01

maintenance even though we're hitting

45:03

the slash endpoint right that means that

45:04

we are actually getting a 5xx

45:06

back from nginx and to kind of highlight

45:09

why that's happening

45:10

it's because if we go to our nginx

45:14

default conf we've actually said that it

45:16

has a proxy pass to localhost 3000

45:19

but now that we've moved to a cluster

45:22

type environment here where each of

45:24

these

45:24

pods are have like the pods now have

45:26

their own ips right

45:28

localhost 3000 doesn't make sense

45:29

anymore this nginx needs to hit this

45:32

cluster ip service and these apps need

45:34

to have this cluster ip service and so

45:36

on

45:37

now if you come to the kubernetes

45:38

dashboard which let's boot it up

45:41

quickly again

45:46

we can see that each cluster ip is

45:49

exposing

45:50

um we can see that each cluster

45:53

each cluster ip service is exposing an

45:56

an ip that we can consume so technically

45:59

our

46:00

our nginx pod needs to hit this app

46:02

server

46:03

ip here or rather the proxy pass has to

46:05

hit this

46:06

and then every call that we make from

46:08

our from our node server by the way

46:11

which is here as well where we hit low

46:13

close 4000

46:14

also has to hit this specific ip but

46:17

here's the thing

46:18

um something that we configure here in

46:20

our local

46:22

kubernetes deployment may not hold true

46:25

when we go to another coupon it is

46:27

environment right let's say we have a

46:28

production environment that we needed

46:30

like we're testing here and we need to

46:31

take this to

46:32

a production environment uh that someone

46:34

else is offering

46:35

we we cannot be guaranteed that these

46:37

cluster ips are going to be the same

46:39

right and kubernetes does solve this

46:42

through

46:42

service name name discovery right

46:46

essentially what you can do is you can

46:50

go in to any place that you want to

46:52

reference another

46:53

uh like another pod or another service

46:56

and you can reference them by

46:58

name what that means is if you if you

47:02

want nginx to hit our app server cluster

47:04

ip service

47:04

instead of giving it an ip we can rather

47:07

just give it the cluster

47:09

the service name itself so i can

47:12

now tell nginx to proxy pass it to app

47:15

server cluster ip service

47:18

and now the this name gets resolved

47:21

by the cluster whenever calls are made

47:23

to this

47:24

to like the dns resolution does happen

47:26

within the cluster for this

47:27

for this domain name so let's add this

47:30

here

47:30

and similarly we'll have to make one

47:32

change in our app server

47:34

to also consume the user service cluster

47:37

ip servers instead of localhost 4000

47:40

right but now there is one concern here

47:44

which is

47:44

that if i now run this locally this is

47:47

going to

47:47

start failing because this doesn't

47:49

resolve to anything right

47:50

so here we can probably put a small

47:52

check

47:55

saying that my response can either come

47:57

from

48:01

localhost or from a cluster ip service

48:04

based on my node env which we've powered

48:07

through the deployment uh

48:09

resource manifest if

48:13

so we can say that if the node dnv is

48:17

production

48:17

then my response will be from this

48:19

cluster ip service

48:22

else my response is going to be from

48:27

localhost 4000 so this should ensure

48:30

that we don't break

48:31

a local development environment for this

48:35

so now that now that we have this we are

48:38

also powering the node by the way from

48:40

here

48:42

in deployment yaml so we can pass in our

48:44

environment variables here

48:45

now let's rebuild the images

48:49

and use the new images in our

48:51

deployments so that the

48:52

end to end cluster starts working as

48:54

expected

48:55

okay so let's first rebuild

48:59

our app server which is what we've

49:00

changed and let's make it v2 now

49:10

similarly let's rebuild nginx

49:16

app engine x v2 and we don't necessarily

49:20

have to rebuild

49:21

our our user service because that hasn't

49:23

changed

49:24

right and now that we have new images

49:27

let's go back to our

49:28

deployment yaml in our app deployment

49:31

yaml we just need to change our image to

49:33

v2

49:34

and let's go to our nginx deployment

49:36

yaml and change this to v2 as well

49:40

let's just verify once that both of

49:42

these

49:43

app engine x and app server are

49:44

available as v2 and now let's

49:47

apply

49:51

the app deployment first so we can see

49:54

that that went through

49:59

so now we can see that a bunch of our

50:01

app servers are now terminating and new

50:03

ones are

50:04

running and we can also see that they

50:06

were spun up quite recently

50:08

and over the course of time we can see

50:10

that the complete handover from v1 to v2

50:14

has happened

50:15

so we are back to only four running

50:17

containers and

50:21

the ones that were terminating are now

50:22

completely terminated and now to confirm

50:24

that we are now running v2

50:26

in this environment we can go back to

50:27

minicube

50:29

the minicube dashboard and

50:33

if we open up any deployment we can see

50:35

that we have our app server

50:37

app server deployment that is

50:40

now pointing to

50:45

the images app server v2 right

50:48

which means that we have you know

50:50

configured a new

50:52

version of the app to go out and

50:54

something that's crucial here

50:56

is if we go back to the age of every pod

50:59

we can see that none of the other pods

51:02

have changed it's strictly only the app

51:04

deployment that has

51:05

gone through which means that only the

51:06

app server code has

51:08

spun up new new versions of the of the

51:10

code on the cluster

51:12

now let's also do that for nginx so

51:14

let's

51:16

cube ctl apply minus f

51:19

the nginx deployment yaml because

51:22

there's a new version of the nginx image

51:24

as well

51:24

and we can see that the deployment got

51:26

configured

51:27

you can get the pods and we can see that

51:29

the nginx

51:30

port the old one was is terminating and

51:32

the new one is now spinning up

51:34

and give it enough time and

51:38

the pod has now like it was terminating

51:41

at this point and now it's completely

51:42

been removed from the cluster

51:45

now let's open up mini cube

51:48

and tunnel the

51:51

nginx load balancer service and now

51:53

instead of the 5xx page we now get the

51:56

page that's rendered directly from our

51:57

app server

51:58

so the proxy pass from nginx to the node

52:01

server is

52:02

working uh correctly we can also use the

52:05

health check endpoint

52:06

to get the response back from the

52:09

from the app server and now to truly

52:12

check if

52:12

it works end to end let's hit the api

52:14

slash users endpoint

52:16

which by the way just to

52:19

reiterate calls the user service cluster

52:23

ap service and returns the users from

52:25

there

52:26

so now hitting slash api users we can

52:29

now see the data for the

52:30

for the for the users now being passed

52:32

from user service

52:33

to the node to the app server and from

52:36

the app server through nginx and back to

52:37

us

52:38

so now we've essentially constructed

52:40

this entire cluster

52:41

with all of these services now running

52:43

in front of these deployments

52:45

and anytime there's any code change that

52:46

we need to do we can just go to a

52:48

deployment.tml file

52:50

change the new change the tag version or

52:52

change the replica account and reapply

52:53

the deployment to have a new version of

52:56

or or the new

53:00

look of our cluster up and running as we

53:04

see fit

53:05

so while the resource manifest files

53:07

provide a very declarative way for us to

53:10

control

53:10

our pods and our services in our cluster

53:14

we can already see that it's getting a

53:15

little bit out of hand with the number

53:17

of

53:17

deployment files that we're maintaining

53:19

and the number of service files that

53:20

we're maintaining

53:21

and this is for a simple application

53:22

that has two two services

53:25

and an nginx layer on top of it now if i

53:28

if our cluster gets slightly more

53:29

complex

53:30

with more uh services coming into play

53:33

we have a lot of these yaml files that

53:34

we have to start

53:35

uh like paying at paying attention to

53:38

and orchestrating the right way

53:39

not to mention that we have only talked

53:41

about two resource manifests here

53:43

technically there are a lot more

53:45

resources that you can apply to your

53:46

cluster such as auto scaling

53:48

configurations

53:49

and like config maps and dynamic configs

53:53

and so on

53:54

so there is a there is a significant

53:57

overhead here

53:59

not to mention that there's another

54:00

problem which is the fact that if you

54:02

see

54:02

the environment variables that we're

54:04

passing in and the replica account that

54:05

we're passing in

54:06

all of these are sort of set in stone

54:09

for a certain type of environment

54:11

for instance here i could say that this

54:14

deployment

54:15

yaml here for my app server gives me a

54:18

good idea of how my production cluster

54:20

is going to be but let's say

54:21

i have a staging environment that needs

54:23

a different env pass to it

54:25

and a different replica account right

54:26

because maybe the staging

54:28

staging cluster has a little less

54:31

resources to use so maybe i want like

54:33

one replica for this

54:35

server on a staging environment and i

54:37

also want to pass in my node and node

54:38

and we are staging here

54:40

i could the easiest way would be to have

54:42

two duplicates

54:43

of this deployment yaml one for

54:46

production so you can have deployment

54:47

hyphen production.yaml and deployment

54:49

hyphen staging.yaml

54:51

but then that's just two environments

54:52

right what if i have

54:54

uh more permutations and combinations of

54:56

the different values i provide here

54:58

that's steadily going to linearly

55:00

increase with each

55:03

each type of variant of my application

55:05

that i'm going to have

55:06

so all of these are potential problems

55:10

that you could run into when you have

55:12

kubernetes running your applications at

55:14

scale and

55:15

uh so to solve this problem

55:18

we have something called helm which sits

55:20

as an abstraction on top of the resource

55:23

manifest that we have

55:24

as part of our kubernetes infrastructure

55:26

and what helm allows you to do

55:28

is it allows you to think simply in

55:31

terms of

55:31

the blueprint for your cluster so you

55:34

define

55:35

what resources need to be part of your

55:37

cluster and also what

55:39

values need to be passed to these these

55:42

resources

55:43

and all you have to do is think in terms

55:46

of this blueprint and generate something

55:48

called a helm chart

55:49

applying a helm chart to a kubernetes

55:51

instance uh will spin up the entire

55:54

cluster for you

55:54

and similarly uh uninstalling your helm

55:57

instant

55:58

helm chart would also remove the entire

56:00

cluster in a single go

56:01

and you can upgrade this chart with any

56:03

smaller changes that you have

56:04

to make over time so helm

56:08

is available to install directly from

56:11

from a script which is available on the

56:13

helm documentation site

56:15

so once you have helm you should be able

56:17

to check if it's up and installed

56:19

using helm version so here we can see

56:21

that it's running

56:22

version 3.4.0 but

56:25

what is this whole helm chart uh concept

56:28

right

56:29

so what a helm chart is is again a

56:32

simple

56:33

yaml file that defines uh what your

56:36

chart name is

56:37

what your version of your chart is and

56:40

what does the chart work upon

56:42

so to kind of highlight how this how all

56:44

of this works let's create a

56:46

file called uh called khs and let's

56:49

create

56:49

a chart.yaml file inside it right

56:53

so this chart.yaml file is going to have

56:56

a name so let's call this our um

56:59

our app cluster and

57:02

it's also going to have a version so

57:04

let's call this version 0.1.0.0

57:08

right now this chart is everything that

57:11

we need to

57:12

to tell helm that there is something

57:14

that i want to install

57:16

to uh to a kubernetes

57:19

environment and the name of the chart is

57:22

going to be called app cluster and this

57:23

is the version for it

57:24

now what does this chart work upon like

57:27

i said it

57:28

takes care of all of the all of the

57:30

resources for you all you just need to

57:32

know is what are the resources that you

57:33

want to put into your

57:34

into your uh into your environment and

57:37

the way that it knows that

57:38

is using this templates folder so

57:42

if we all we have to do is move in all

57:45

of these deployments and services that

57:47

we have in separate folders

57:48

into this templates directory and

57:51

now helm will be able to understand that

57:53

yes these are these are the different

57:55

or the various resources that i want to

57:58

install and deploy to my cluster

58:01

so let's move in our app deployment and

58:05

app service

58:06

and let's just call it call it something

58:09

different so it doesn't have to be

58:10

called the same thing so i

58:11

call it app deployment and app service

58:17

app service i can also move in

58:21

my nginx deployment and my nginx service

58:26

so let's rename this as well nginx

58:28

deployment

58:30

and my nginx service and let's also move

58:34

in

58:34

my user service deployment and my user

58:36

service

58:38

service so i can call this my user

58:40

service

58:42

service service and my

58:46

user service deployment so now that

58:49

we've moved all of this here

58:51

we've essentially co-located all of the

58:53

different resources that we need to

58:55

install in our cluster and all of these

58:58

are

58:59

all of these will now be orchestrated by

59:01

helm

59:02

which i'll show you in a bit but another

59:05

key thing that i want to touch upon

59:06

is the values.yaml which is another key

59:10

component

59:11

to a helm chart so what this values.ml

59:15

file

59:16

allows you to do is provide a

59:19

yaml file of any format there's not a

59:21

fixed format here

59:23

but you can provide keys and values in

59:24

this yaml file and you can use those

59:27

keys and values inside your various

59:28

templates

59:29

which should potentially solve a problem

59:31

about having different environment

59:32

variables and different

59:34

uh configurations for our different

59:36

environments right

59:37

so let's let's take the app deployment

59:39

as an example here

59:41

so let's say i want to configure uh

59:44

the replicas and i also want to

59:46

configure the the

59:47

node env here right uh to start uh to

59:50

start simple

59:51

so let's just close a couple of files

59:53

and simply concentrate on the app

59:55

deployment and our values.yaml

59:57

so i can create a namespace called app

59:59

server in my values.yaml

60:01

and i can say that the name of my app

60:04

server is going to be called app server

60:07

right just a simple key called name

60:09

whose value is app server

60:10

and i also want to provide some details

60:13

about my image

60:14

i want to my image name

60:17

is going to be called app server my

60:20

image tag

60:21

is v2 all right and

60:24

let's also say that my uh

60:28

exposed port

60:31

is 3000 right and

60:34

the replicas that i want to have for

60:36

this by default is 4

60:38

but based on the environment i can

60:39

change it so i have this um this map

60:42

created in my in my values at yaml so

60:44

now let's see how we can use this

60:46

to parameterize our app deployment

60:50

to make it seem this for us to integrate

60:51

this in different environments

60:53

so the syntax that's used here is based

60:56

on the golang templating language

60:58

so let's plug in a couple of these

60:59

values let's replace the replicas for

61:01

now

61:02

so i don't want four to be baked into my

61:04

app deployment but rather

61:06

control through my values.dml file so i

61:08

can say values

61:10

dot app server dot replicas

61:14

is what is going to be the value for

61:16

this replicas key

61:17

so have app server and replicas right

61:21

and uh similarly let's just change up

61:24

some stuff here

61:25

so i can also interpolate the

61:28

the values it doesn't always have to be

61:30

a single value so for example here my

61:32

image

61:33

is going to be dot values

61:36

dot app server image

61:40

dot name right

61:43

and this is colon for the tag

61:46

and values dot appserver.image.tag

61:52

right so we have essentially

61:53

interpolated two values into a single

61:55

string

61:56

which is joined by this uh this colon

61:58

here

61:59

and we also have the configuration for

62:01

the exposed port

62:02

so let's use that here so i have dot

62:07

values dot app server

62:11

dot image dot exposed port

62:15

right and uh another thing that we

62:18

wanted to do was we wanted to have

62:19

different environment variables for

62:21

different uh

62:22

environments that we wanted to deploy to

62:24

the default is production

62:25

so let's also have a key called env in

62:27

node env and

62:29

use that here so dot values

62:32

dot app server dot env dot no dmv

62:36

right and another thing that we can

62:39

probably use is this name

62:40

key to kind of replace all of these app

62:42

server

62:43

uh instances so that we can we can be

62:45

sure that we always have a single source

62:47

of truth rather than having it

62:49

split across multiple places so let's

62:52

just

62:52

select that

62:56

and change all of these instances to dot

62:59

values values.appserver.name

63:05

and again this is just a way for us to

63:07

ensure that some consistency

63:09

so that we don't make mistakes where

63:10

maybe potentially

63:12

we've introduced a typo here in the

63:13

match labels and suddenly my deployment

63:15

is not

63:16

annotated correctly

63:19

so now we have this app deployment that

63:21

has essentially been templatized and all

63:23

of the values are now flowing in through

63:24

our values.yaml

63:26

let's also do the same thing for our app

63:27

server right so we can call we can add a

63:30

key call service doesn't have to be call

63:32

service it can be called anything

63:33

there's no uh fixed uh format

63:37

and this is kind of where you'll start

63:39

to see the benefit of having it

63:40

templatized and having a single source

63:42

of truth

63:43

so we have this app server let's just

63:45

change this

63:46

to also take our values.appserver.name

63:50

right and it's a cluster ip service so

63:53

let's also just add that here so

63:55

type is cluster ip and let's use that

63:59

here

64:01

values dot app server service

64:04

dot type so tomorrow if you want to swap

64:07

it out for load balancer we can just

64:08

come here and change this one value

64:10

and here is where we can start seeing

64:13

the benefit of having a single source of

64:15

truth so we have this exposed port

64:17

right and we're using that to define

64:20

what our container port is going to be

64:22

but we also need to ensure that our app

64:24

server or rather our trusted ip service

64:26

is also talking to the same target port

64:29

so to maintain the same value we can

64:31

just point to the same

64:33

values dot app server dot image dot

64:36

exposed port and now we can be certain

64:40

that

64:41

since there's a single source of truth

64:42

again changing this one value will

64:44

ensure that the deployment will

64:47

see the right container port and the app

64:48

service will also forward the

64:50

request from port 80 to the to the

64:51

exposed port correctly

64:53

and let's also change the selector app

64:56

server dot name

65:00

and there we have it so now we've

65:03

essentially templatized both our service

65:05

as well as our deployment and the values

65:06

for it are coming through our values at

65:08

yaml

65:09

so let's just take a quick minute to

65:11

templatize the rest of our deployments

65:13

and services and then let's see how

65:15

all of this places uh well together when

65:19

we do a helm install

65:26

[Music]

65:48

foreign

65:50

[Music]

65:59

so now let's let's see what we've done

66:01

so far

66:02

so we have our app server which has some

66:05

values we have nginx

66:07

where we see that this is our image name

66:09

image tag expose port we have one

66:11

replica and the service type is load

66:13

balancer

66:14

and user service has a name the image is

66:16

user service tag

66:18

is v1 exposes 4000 and 2 replicas

66:21

and we've used those parameters so we've

66:24

used all the user service

66:25

values in our user service deployment

66:28

we've used the same user service values

66:30

in the service as well

66:32

and similarly with nginx we've used all

66:34

the nginx values in the nginx deployment

66:37

as well as in the nginx server so now

66:39

that we have

66:41

this chart yaml and the values yaml

66:44

we can now use the helm command to

66:48

use this chart and deploy it to our

66:52

our running kubernetes instance here in

66:54

the in the

66:57

in the docker context right so

67:00

first things first let's first purge all

67:02

of the pods that we have

67:04

running so that we can see how helm uh

67:06

helps you set up everything from scratch

67:08

so you can use the cube ctl

67:11

delete pods or rather let's delete the

67:14

deployments first

67:15

rather than the pods

67:19

so so now we should see that all the

67:22

pods are terminating

67:24

and let's also clear up all the services

67:28

and we can see that all the services

67:29

have been destroyed and now if we get

67:32

pods

67:33

they're all in the state of terminating

67:34

still and we get all the services

67:36

the services have also been purged so

67:39

let's just wait till all the pods are

67:41

done

67:42

so now that now we can see that the

67:44

normal pods which means that we we have

67:45

a completely empty cluster

67:47

no services no pods and we can confirm

67:49

this by using the dashboard again

67:52

uh minicube dashboard we can jump in

67:54

here and we can see

67:56

that there are no deployments

67:59

no pods and no services this is the

68:02

default service but no custom services

68:04

that we've

68:05

uh configured available right now in our

68:07

cluster

68:08

so which means that we have a completely

68:09

clean installation

68:11

so now we can use helm

68:14

to install this entire chart which is

68:17

what we've created here under the kth

68:18

folder

68:19

uh the chart configuration is available

68:21

in chart.yaml

68:22

the valleys of gamble contains all the

68:24

values to work upon the

68:26

templates that we have for our various

68:29

resources

68:30

so we can come back here to uh helm

68:32

install

68:33

and what helm install asks you is for a

68:37

path to the to the to the chart folder

68:41

and let's just see this run as a dry run

68:44

before we do the actual installation

68:46

and let's also ask you to generate a

68:48

default name for us

68:51

so if you notice here we can see

68:55

that all of our resource files are just

68:57

being console logged to us because we

68:59

ran it as a dry run

69:00

but what's very very neat here

69:04

is that all of our template values have

69:06

been replaced

69:07

so if you see here we can see that the

69:09

nginx name has been replaced everywhere

69:11

the nginx image name has been replaced

69:13

correctly

69:13

replicas uh the same thing with the user

69:16

service deployment

69:17

so we have a single value of gamma

69:20

that's not driving all of these

69:21

templates

69:22

which means that we can technically use

69:24

our values yaml

69:25

to drive different values for different

69:27

environments

69:28

but before we get there let's not run it

69:31

as a dry run now and let's do an entire

69:33

installation

69:34

of the chart folder and let's generate a

69:36

name

69:39

and we can see that the deployment has

69:42

gone through successfully

69:44

and let's just open mini cube

69:48

and or rather open the kubernetes

69:50

dashboard in minicube

69:52

and in a single installation command we

69:54

can see that three deployments have been

69:56

pushed to our cluster of these

69:58

deployments are running all of these

70:00

pods we can see one two three

70:02

four instances of wrap of the app server

70:04

one instance of the nginx deployment and

70:06

two instances

70:07

or two replicas of the user service we

70:10

can also see that our

70:12

services are up and running we have our

70:14

app server cluster ip servers our user

70:15

service cluster ip service and the node

70:17

nginx load balancer this is still

70:19

waiting because we have to do the

70:20

tunneling through mini cube but

70:22

in a production environment this would

70:23

have resolved to an external ip

70:26

and now just to check if

70:30

this is working correctly let's

70:33

fire up the tunnel to our load balancer

70:35

service and we can see that everything

70:37

is running as expected

70:38

we can go to slash api slash users and

70:41

we can see that the data is being

70:43

funneled

70:43

end to end now through the cluster

70:48

now helm is great in the sense that if

70:50

we do a helm

70:51

list we can see the see the various

70:54

running

70:55

uh helm installations that are deployed

70:57

to our

70:58

cluster we can also see that this is the

71:00

chart name and the chart version

71:02

and it's good practice to maintain a

71:06

proper symbol for the for the for the

71:08

chart version

71:09

so charts can be reused by other

71:13

uh charts so similar to how docker

71:16

images have base images right

71:17

you can have a base chart version also

71:20

so if you want to share this chart with

71:21

another

71:22

team or or to the public you can have

71:26

your chart name and a version associated

71:27

with it and actually uh

71:29

like share this and other folks can use

71:32

this as a dependency for their chart

71:34

which means that you bring all of your

71:35

resource templates and the values yaml

71:37

and they can then extend upon that to

71:39

build their use cases

71:40

so it's a good practice to follow good

71:42

semver which means that anytime there's

71:44

a change to the chart itself right not

71:46

the values yammer that's

71:47

slightly debatable but when you have

71:50

changes to the resource templates

71:52

or any new resource templates get added

71:54

it's it's good to update this version

71:57

so let's let's make a small change to

71:59

see how a

72:00

second deployment can happen to the same

72:02

uh cluster

72:03

so let's go back to our code base pull

72:06

out our user service

72:08

and let's say we want to add another

72:11

user to our list right so whose name is

72:14

jordando right so

72:17

at this point in time we need to

72:19

recreate another docker image which

72:21

contains the new code

72:23

and then use a docker image in our

72:25

values yaml

72:26

to configure the new value for our

72:29

for our deployment so we can come back

72:33

here

72:33

we can do a docker build and we can

72:36

build our user service again

72:37

except this time let's tag it as v2

72:39

because we have a new uh

72:41

version of the of the code so we've

72:44

tagged this as v2

72:45

let's also check if the image is

72:47

available and we can see that user

72:49

service v2 is available now

72:51

now let's jump back to our values.yaml

72:54

so if you go to kth

72:55

values or yaml we can see that user

72:57

service image tag is v2

73:00

let's bump that up to sv1 let's bump

73:02

that up to v2

73:04

and let's do a helm upgrade

73:12

upgrade of the same installation

73:16

and let's provide the path to the chart

73:21

so now what helm is doing is essentially

73:23

taking the chart that we have the new

73:25

version of the chart and applying it on

73:26

the same

73:27

installation that we had earlier but

73:30

with the new values of gamble and that's

73:31

why we have us

73:32

we have a new revision of the of the

73:34

deployment

73:35

so now if you do a cube ctl get pods

73:37

what's interesting here

73:39

is the old user service deployments are

73:41

now being terminated

73:42

and new ones have taken the place if you

73:44

see here these are just a couple of

73:45

seconds ago

73:47

but none of the other pods have been

73:49

touched in any form

73:51

right which means that you can

73:54

use the same chart to deploy a version

73:57

of your cluster

73:58

but there is a clean diff that's done to

74:01

ensure that

74:01

running pods that have had no change in

74:04

the new version of the chart are not

74:06

touched and

74:07

are running as they were before so let's

74:10

uh ensure all the terminating pods are

74:12

gone and they have

74:14

and to actually see if the code is up

74:16

and running within

74:17

within with the new user that we've

74:18

added let's again tunnel

74:20

to the load balancer service through

74:22

mini cube service

74:25

and let's hit slash api slash users

74:28

and we can see that the new user is now

74:30

available as part of the data array

74:32

which means the new

74:34

new docker image has spun up

74:37

new containers in the cluster and those

74:39

containers are now serving the new code

74:41

so this is how you can use helm

74:45

to for all intended purposes just

74:48

envision how your cluster is going to

74:50

look

74:50

along with the various values uh that

74:53

you want to

74:54

that you want to use for this version of

74:55

your blueprint and use these values in

74:58

templatized

74:59

uh resource management manifest files

75:02

and the beauty of this is if since these

75:05

are templatized

75:06

you could potentially override these

75:08

values or yaml

75:10

values through cli arguments when if you

75:13

want to deploy to a different

75:14

environment so these are all

75:15

default values that we're applying to

75:17

our templates

75:18

but if you have a separate environment

75:20

let's say like a staging environment

75:22

you can use the helm install cli uh to

75:25

pass in a different value for app server

75:27

env for instance or app server replicas

75:30

for instance

75:30

based on the environment that you want

75:32

to deploy to so that allows

75:34

these templates to be far more generic

75:37

and we don't have to have

75:38

we don't have to have copies for every

75:39

environment that we want to deploy to

75:41

so similar to how we have helm installed

75:43

to spin up an entire cluster

75:45

and send helm upgrade to upgrade the

75:47

values in a cluster

75:48

we can use the helm uninstall command

75:52

to completely purge a cluster as well so

75:54

in like instead of having to go and

75:56

delete all of our pods and all of our

75:57

deployments and

75:58

so on we can just use our chart which is

76:02

anyway like a blueprint of what we've

76:03

deployed

76:04

as a stencil to also note or also keep

76:07

note of what needs to be removed when

76:08

you want to remove a

76:10

installation so i can just do a helm

76:12

uninstall and the name of the

76:14

of the helm installation and

76:17

it will tell us that the release has

76:18

been uninstalled and now if we do a cube

76:20

ctl get pods we can see that all of the

76:22

pods that are controlled by this chart

76:24

are being terminated

76:25

we can see the deployments have been

76:27

purged

76:28

and we can also see that the services

76:30

have been purged as well apart from the

76:31

default one but

76:32

the ones such as the user service

76:34

cluster ip service

76:36

uh app server cluster ip service as well

76:38

as the

76:39

load balancer service have all been

76:40

purged as well so

76:42

you know in a single command we can get

76:44

an entire cluster up and running

76:46

in a single command we can have a new

76:47

version of a cluster installed

76:49

and if the single command we can have

76:51

the entire

76:52

cluster purged as well so this

76:55

is in a nutshell how we can get a

76:58

node.js and an nginx application up on a

77:02

kubernetes cluster

77:03

using helm i hope you guys found this

77:05

useful and i'll see you in the next one

77:18

[Music]

77:29

foreign

Interactive Summary

This video provides a comprehensive guide on containerizing Node.js and Nginx applications and deploying them to a local Kubernetes cluster using minikube and helm. It covers the end-to-end process: from creating Dockerfiles and building images, to setting up Kubernetes deployments and service manifests, and finally utilizing Helm charts to simplify configuration and deployment management across different environments.

Suggested questions

4 ready-made prompts