<p>I have a running Elasticsearch STS with a headless Service assigned to it:</p>

<p>svc.yaml:</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  name: elasticsearch
  namespace: elasticsearch-namespace
  labels:
    app: elasticsearch
spec:
  selector:
    app: elasticsearch
  clusterIP: None
  ports:
    - port: 9200
      name: rest
    - port: 9300
      name: inter-node
</code></pre>

<p>stateful.yaml:</p>

<pre><code>apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: es-cluster
  namespace: elasticsearch-namespace
spec:
  serviceName: elasticsearch
  replicas: 3
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      containers:
      - name: elasticsearch
        image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
        resources:
            limits:
              cpu: 1000m
            requests:
              cpu: 100m
        ports:
        - containerPort: 9200
          name: rest
          protocol: TCP
        - containerPort: 9300
          name: inter-node
          protocol: TCP
        volumeMounts:
          - name: elasticsearch-persistent-storage
            mountPath: /usr/share/elasticsearch/data
        env:
          - name: cluster.name
            value: k8s-logs
          - name: node.name
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: discovery.seed_hosts
            value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch"
          - name: cluster.initial_master_nodes
            value: "es-cluster-0,es-cluster-1,es-cluster-2"
          - name: ES_JAVA_OPTS
            value: "-Xms512m -Xmx512m"
      initContainers:
      - name: fix-permissions
        image: busybox
        command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: elasticsearch-persistent-storage
          mountPath: /usr/share/elasticsearch/data
      - name: increase-vm-max-map
        image: busybox
        command: ["sysctl", "-w", "vm.max_map_count=262144"]
        securityContext:
          privileged: true
      - name: increase-fd-ulimit
        image: busybox
        command: ["sh", "-c", "ulimit -n 65536"]
        securityContext:
          privileged: true
  volumeClaimTemplates:
    - metadata:
        name: elasticsearch-persistent-storage
        labels:
          app: elasticsearch
      spec:
        accessModes: [ "ReadWriteOnce" ]
        storageClassName: elasticsearch-storageclass
        resources:
          requests:
            storage: 20Gi
</code></pre>

<p>The question is: how to access this STS with PODs of Deployment Kind? Let's say, using this Redis POD:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-ws-app
  labels:
    app: redis-ws-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-ws-app
  template:
    metadata:
      labels:
        app: redis-ws-app
    spec:
      containers:
      - name: redis-ws-app
        image: redis:latest
        command: [ "redis-server"]
        ports:
        - containerPort: 6379
</code></pre>

<p>I have been trying to create another service, that would enable me to access it from the outside, but without any luck:</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  name: elasticsearch-tcp
  namespace: elasticsearch-namespace
  labels:
    app: elasticsearch
spec:
  selector:
    app: elasticsearch
  ports:
  - protocol: TCP
    port: 9200
    targetPort: 9200
</code></pre>

Artur Drożdżyk
<p>You would reach it directly hitting the headless service. As an example, this <code>StatefulSet</code> and this <code>Service</code>.</p>

<pre><code>apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 4
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web

---

kind: Service
apiVersion: v1
metadata:
  name: nginx-headless
spec:
  selector:
    app: nginx
  clusterIP: None
  ports:
    - port: 80
      name: http
</code></pre>

<p>I could reach the pods of the statefulset, through the headless service from any pod within the cluster:</p>

<pre><code>/ # curl -I nginx-headless
HTTP/1.1 200 OK
Server: nginx/1.19.0
Date: Tue, 09 Jun 2020 12:36:47 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 May 2020 15:00:20 GMT
Connection: keep-alive
ETag: "5ecd2f04-264"
Accept-Ranges: bytes
</code></pre>

<p>The singularity of the headless service, is that it doesn't create <code>iptable</code> rules for that service. So, when you query that service,  it goes to kube-dns (or CoreDNS), and it returns the backends, rather then the IP address is the service itself. So, if you do <code>nslookup</code>, for example, it will return all the backends (pods) of that service:</p>

<pre><code>/ # nslookup nginx-headless

Name:      nginx-headless
Address 1: 10.56.1.44
Address 2: 10.56.1.45
Address 3: 10.56.1.46
Address 4: 10.56.1.47
</code></pre>

<p>And it won't have any <code>iptable</code> rules assigned to it:</p>

<pre><code>$ sudo iptables-save | grep -i nginx-headless
$
</code></pre>

<p>Unlike a normal service, that would return the IP address of the service itself:</p>

<pre><code>/ # nslookup nginx

Name:      nginx
Address 1: 10.60.15.30 nginx.default.svc.cluster.local
</code></pre>

<p>And it will have <code>iptable</code> rules assigned to it:</p>

<pre><code>$ sudo iptables-save | grep -i nginx
-A KUBE-SERVICES ! -s 10.56.0.0/14 -d 10.60.15.30/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.60.15.30/32 -p tcp -m comment --comment "default/nginx: cluster IP" -m tcp --dport 80 -j KUBE-SVC-4N57TFCL4MD7ZTDA
</code></pre>
