# Service: kubectl expose

Another way to create a service is by using `kubectl expose` command.

```bash
kubectl expose <resource-type> <resource-name> --port=<port> --target-port=<target-port> --type=<type>
```

* `<resource-type>`: Type of Kubernetes resource (**pod**, **deployment**, **replicaset**, etc.).
* `<resource-name>`: Name of the resource to expose.
* `--port`: The external port to expose.
* `--target-port`: The port on the container to forward traffic to.
* `--type`: Type of service (ClusterIP, NodePort, LoadBalancer, or ExternalName).
* `--name`: Name of newly created service.

## Expose as ClusterIP Service

First lets create a simple deployment object using `nginx` image with name `my-server`.

```bash
➜ kubectl create deployment my-server --image=nginx
deployment.apps/my-server created
```

```bash
➜ kubectl get deployments.apps                                      
NAME        READY   UP-TO-DATE   AVAILABLE   AGE
my-server   1/1     1            0           10s
postgres    1/1     1            1           25h
simple-go   3/3     3            3           25h
```

Then lets create a service with type `ClusterIP` using `kubectl exec` command. Since `ClusterIP` is the default type we don't need to specify the `--type` argument.

```bash
➜ kubectl expose deployment my-server --port=80 --target-port=80
service/my-server exposed
```

```bash
➜ kubectl get svc my-server
NAME        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
my-server   ClusterIP   10.97.240.5   <none>        80/TCP    1m2s
```

As we can see above the command will create a service name `my-server` that exposes deployment named `my-server`. We also can get the details in `yaml` format using command `kubectl get service my-server -o yaml`.

```yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2025-02-10T06:03:41Z"
  labels:
    app: my-server
  name: my-server
  namespace: default
  resourceVersion: "129776"
  uid: 618624cb-2f7e-466e-992d-ecfaf400fb72
spec:
  clusterIP: 10.97.240.5
  clusterIPs:
  - 10.97.240.5
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: my-server
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}
```

## Expose as NodePort Service

Lets delete our previous service and then expose our deployment again as `NodePort` service. We need to delete the previous service because the expose command by default will name the service same as deployment name.

```bash
➜ kubectl delete svc my-server 
service "my-server" deleted
```

Because `NodePort` is not the default service type, we need to explicitly specify the service type using `--type` in expose command.

```bash
➜ kubectl expose deployment my-server --type=NodePort --port=80 --target-port=80
service/my-server exposed
```

```bash
➜ kubectl get svc my-server 
NAME        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
my-server   NodePort   10.100.253.32   <none>        80:31775/TCP   8s
```

Now it exposed as `NodePort` and you can try to access it using the minikube IP and the service PORT. But if you use minikube on Mac using docker driver like me you will need `minikube service` to expose it.

## Expose as LoadBalancer Service

No lets create another service but with type `LoadBalancer`. This time we explicitly specify the service name using `--name` argument.

This command below will create a service with type `LoadBalancer` and name `my-server-lb`.

```bash
➜ kubectl expose deployment my-server --type=LoadBalancer --name=my-server-lb --port=80 --target-port=80
service/my-server-lb exposed
```

```bash
➜ kubectl get svc my-server-lb 
NAME           TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
my-server-lb   LoadBalancer   10.96.60.45   <pending>     80:30309/TCP   59s
```

Run `minikube tunnel` on the other terminal and test it using curl.

```html
➜ curl http://localhost       

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

## Expose Pod Directly

We can also directly expose a pod but this is not recommended in production.

For example lets expose the `my-server` pod.

```bash
➜ kubectl get pods 
NAME                         READY   STATUS    RESTARTS   AGE
my-server-78b5bb4ccc-7cbxf   1/1     Running   0          31m
postgres-f8f589d5b-59rw8     1/1     Running   0          25h
simple-go-5dc4557ffc-c24fp   1/1     Running   0          25h
simple-go-5dc4557ffc-d6tz6   1/1     Running   0          25h
simple-go-5dc4557ffc-gv4fv   1/1     Running   0          25h
```

```bash
➜ kubectl expose pod my-server-78b5bb4ccc-7cbxf --port=80 --target-port=80
service/my-server-78b5bb4ccc-7cbxf exposed
```

The command above will create a `ClusterIP` service that expose the pod `my-server-78b5bb4ccc-7cbxf`.

This is not recommended because as we can see below this service is tied to a specific pod. So if that pod is replaced or upgraded, the service will not work.

```bash
➜ kubectl get svc my-server-78b5bb4ccc-7cbxf -o yaml
```

```yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2025-02-10T06:34:09Z"
  labels:
    app: my-server
    pod-template-hash: 78b5bb4ccc
  name: my-server-78b5bb4ccc-7cbxf
  namespace: default
  resourceVersion: "131264"
  uid: 98ef311b-0054-4023-8d83-ca5b0bc9c025
spec:
  clusterIP: 10.99.77.89
  clusterIPs:
  - 10.99.77.89
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: my-server
    pod-template-hash: 78b5bb4ccc
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}
```

## References

* <https://kubernetes.io/docs/reference/kubectl/generated/kubectl_expose/>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/cka/05_service_expose.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
