So having a deployment is nice,
but not enough.
I will add a second file here,
and that's the service.yaml file,
where I wanna define the service
for my deployment for this application.
And the service.yaml file of course,
is very similar to the deployment.yaml file,
at least to some extent.
Since it's still a Kubernetes Config File,
we still need to define the API version.
Here, the difference compared to deployment is,
that it's just v1.
And we can see this in the official reference documentation,
there, if you have a look at the service resource,
you see the group is the core group,
and that essentially means that you can omit it.
So it's not core/v1, it's just v1.
Now, I as mentioned before that alone,
also in conjunction with the file name,
won't tell Cooper, Nita is what you wanna create.
Because it ignores the file name,
since that name is totally up to you.
Instead, you need to specify a kind in this case,
the service kind.
Since we wanna create a service resource
and you again see that here in the reference docs as well.
There, you'll also see what else can be defined,
and that's of course again,
the metadata and the specification.
So for the metadata, I again,
wanna give this service a name and I'll name it backend,
the name is of course, up to you.
And then for the spec,
we will again define and configure this service.
And here, if we have a look at the reference doc,
we see that there's again,
a lot we can configure because of course
kubernetes is very powerful and gives us a lot of options.
But again, we typically don't need all these options.
What we do need here though, is a selector.
And I did talk about selectors before.
A selector identifies which other resources
should be controlled or connected to this resource.
In this case here, we wanna define which pods
should be part of this service.
Because as we learned before,
a service object exposes pods
to the cluster or to the outside world.
So you don't control deployments with a service,
but instead pods, but of course,
pods are typically generated by a deployment
nonetheless with that selector here,
we wanna select the individual pods.
Now this elector of the service object
works a bit differently than the one
from the deployment object.
There, we had matchlabels
and then our label key value pairs,
which we wanted to connect.
Now, we had this syntax here
because the deployment resource type is a bit newer.
It has been added more recently, you could say,
even though it's also over here around
for quite some time now.
But the service resource is simply older
and there, the selector is simpler.
You don't have matchlabels below it
because you can only match labels here.
So therefore you directly have
to label key value pairs here.
And I wanna control my ports,
which are created like this,
so which have these labels.
Hence we can copy the labels here and add them here
to selector, just make sure the indentation is correct.
Now, you don't always have to select
by all the labels though.
Maybe that is what you want, but maybe in your project,
you also have another deployment,
which creates ports with an app of second app,
but which does not have a tier of backend.
And whilst these ports
would be part of different deployments,
you maybe wanna group them into the same service.
So you could choose to just select by the app label
and ignore the tier label.
So that all ports which have that app label with that value,
would be controlled by that service,
even if they then have different tiers.
Not something we have here,
but something you can do with selectors,
and definitely the idea behind selectors.
The idea is that you have great flexibility when it comes
to expressing which other resource should be connected to
or controlled by some other resource.
So in this case I'm saying this service selects
and therefor exposes all ports with an app label
with a value of second app.
And that of course means that the ports generated
by this deployment will be exposed by this service.
So that's great, now we know which pods should be exposed,
but we don't know yet how they should be exposed
and which ports should be exposed.
And keep in mind that when we used the imperative approach,
we used the expose command
to expose our first app deployment.
And there we added dash dash port
to decide which port should be exposed.
And we add a dash dash type loadBalancer
to decide how it should be exposed basically.
And we can do the same things here.
Let's start with the ports and you can expose more
than one port, which is why this is named ports.
And therefore you then have a list of ports
that can be exposed.
And there, you typically
always define the protocol being used,
which by default here is TCP.
And then on the same list item the port,
you wanna expose it on,
let's say port 80 and the target port
inside of the container in this case 80 80,
because that is the port,
my application is listening on.
So therefore that's the target port, in the container
and that's then the outside world port
on which this should be exposed.
And if you had multiple ports,
you could also of course do that, right?
So if you had another port, if you had another port,
let's say port 443 you could of course also exposed that.
But we don't have it here, so I'll comment this out.
So that's the ports option now for the type option,
you simply add that next to ports.
So not nested below it, but on the same level as ports,
you add your type.
And there you got the types available,
which I described, clusterIP, which is the default,
which is an internally exposed IP.
So only accessible from inside the cluster,
NodePort to basically expose it on the IP
and port of the worker node
on which it runs and most commonly used loadBalancer.
At least if you want outside world access.
This then utilizes the loadBalancer
off your cluster infrastructure, in this case,
minikubes loadBalancer, and you will get an address,
an outside world reachable address,
which then allows you to reach this service
and therefor the ports exposed by that service.
And in addition, incoming traffic is distributed equally.
And with that, we got our service object defined.
That's our service resource
and that's the service we now wanna create.
And we created now just as we created our deployment,
with kube control, apply dash file service.yaml.
It's always the same command
because it's simply looks into the file
to then find out what it needs to create.
So for now had enter this services created.
So if we now get our services, we will see it here.
And of course we can now expose it with minikube service
and then the name you chose here, so in this case backend.
and this will open up a new browser tab
and you can view your application here.
If it doesn't open a new tab, you can,
of course manually use this URL here.
So this is now working.
This is now how we can create our deployment
and our service in a declarative way.
And this is the way and the approach you typically use
because it's easier to maintain.
You don't always have to re-type commands
and it's less error prone.
If you type a command like to Kube control,
expose command, it's easy to mistype something,
or to forget something.
If you have it in your conflict file,
making changes is easy, you don't have to repeat everything.
You can just change one thing,
and it's also very easy to share.
In addition, if a colleague wrote this,
you can quickly see how something needs to be configured,
and you don't have to ask your colleague on how you should
run this command the next time you're running it.
So that's why the declarative approach
is the recommended approach and why it is the approach
We will use throughout this course.