<p>I am digging into nginx, Kubernetes and SSL as I am trying to deploy my web app onto Kubernetes via Google Kubernetes Engine (GKE).</p>

<p>A little about my project:</p>

<ul>
<li>My frontend is a React web application</li>
<li>My backend is a Node Express API service</li>
</ul>

<p>They are on separate repos (ex: frontend repo and backend repo)</p>

<p>I am planning on using nginx to serve my frontend and proxy requests to my backend.</p>

<p>My question is...</p>

<p>Would it be possible to have both my backend and frontend within the same Kubernetes config yaml file, and if possible, is this best practice to do so?</p>

<p>How I see it is...</p>

<p>In my <code>nginx.conf</code> file, I will have a server section that has a <code>proxy_pass</code> to something like <code>localhost:8000</code>, which is the port of the backend. I would assume this would work if both are within the same container and local network.</p>

<p>I would then probably have a load balancer that points to nginx.</p>

<p>Any help or advice is appreciated! I hope this makes sense (still very new to this)!</p>

<p>Let's start from the beginning. There is too much to say on this topic to put everything in the comments, so let's move it to an answer. If something below isn't entirely clear, don't hesitate to ask.</p>

<p>First of all you need to start from your <strong>application architecture</strong> and try to determine how it is supposed to work, what part should be able to communicate with another one.</p>

<p><strong>Microservices</strong> approach in design of applications is entire broad topic and would deserve rather separate article than attempt to explain it in a single answer. But in a nutshell, all it is about is decoupling the application into separate parts where each of them have a distinct functionality and can be developed, deployed and updated separately. Those elements can be closely related, they can even totally depend on one another but at the same time they are separate entities.</p>

<p><strong>Kubernetes</strong> by its very nature encourages you to follow the above approach. If you read more about <a href="https://kubernetes.io/docs/concepts/workloads/pods/pod/" rel="nofollow noreferrer">Pods</a>, you will see that they are perfectly made for this purpose, for being a kind of wrapper for single <strong>microservice</strong>. This is a simplification to some extent, but I believe it reflects the essence of the matter. In real production environment you can have a set of <code>Pods</code> managed by higher abstraction such as <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" rel="nofollow noreferrer">Deployment</a>, but note that even if you have 3 or more replicas of a single <code>Pod</code> it still represents the same single <strong>microservice</strong>, only scaled horizontaly e.g. to be able to handle bigger load or more requests.</p>

<p>Separate sets of <code>Pods</code> representing different <strong>microservices</strong> can communicate with each other and be exposed to external world thanks to <a href="https://kubernetes.io/docs/concepts/services-networking/service/" rel="nofollow noreferrer">Services</a>.</p>

<p>As you can read in <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/" rel="nofollow noreferrer">kubernetes docs</a>, an <code>Ingress</code> is:</p>

<blockquote>
  <p>An API object that manages external access to the services in a
  cluster, typically HTTP. Ingress may provide load balancing, SSL
  termination and name-based virtual hosting.</p>
  
  <p>Ingress exposes HTTP and HTTPS routes from outside the cluster to
  services within the cluster. Traffic routing is controlled by rules
  defined on the Ingress resource.</p>

<pre><code>    internet
        |
   [ Ingress ]
   --|-----|--
   [ Services ]
</code></pre>
</blockquote>

<p>You should ask yourself if you really want to expose to the external world both your frontend and backend <code>Pods</code>. Typically you don't want to do it. <strong>Backend</strong> by its very definition should act as a... well... as a <strong>backend</strong> of your app :) It is not supposed to be reachable directly by external users but only via <strong>frontend</strong> part of the application so it shouldn't be exposed via <code>Ingress</code>. Only after the <strong>frontend</strong> part of your app receives a request from external user, it makes its own request to the <strong>backend</strong>, retrives some data processed by the backend app and then passes it to the end user. <strong>User doesn't make direct requests to your backend app</strong>.</p>

<p>You can expose via <code>Ingress</code> different parts of your application using different paths (like in the example given in another answer), which can be backed by different <strong>microservices</strong> running in different sets of <code>Pods</code> but still they should be <strong>frontend parts</strong> of your app, <strong>NOT</strong> <strong>backend</strong>.</p>

<p><strong>Backend</strong> <code>Pods</code> is something that you usually expose only within your <strong>kubernetes cluster</strong>, to make it available to other components of your app. For that purpose simple <a href="https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service" rel="nofollow noreferrer">Service</a> of type <code>ClusterIP</code> (which is by the way the default type, automatically chosen when the <code>type:</code> field is not specified) is the way to go.</p>

<p>I would encourage you to read more about different <code>Service</code> <a href="https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types" rel="nofollow noreferrer">types</a> and what they are used for.</p>

<p>You may also want to take a look at the following articles. I believe they will make the whole concept even clearer:</p>

<p><a href="https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/" rel="nofollow noreferrer">Connecting Applications with Services</a></p>

<p><a href="https://kubernetes.io/docs/tasks/access-application-cluster/connecting-frontend-backend/" rel="nofollow noreferrer">Connect a Front End to a Back End Using a Service</a></p>

<p>As to merging different <strong>kubernetes objects</strong> definitions to a single <code>yaml</code> file like in <a href="https://kubernetes.io/docs/tasks/access-application-cluster/connecting-frontend-backend/#creating-the-frontend" rel="nofollow noreferrer">this</a> example, where you can see <code>Service</code> and <code>Deployment</code> defined in a single <code>yaml</code> file and separated with <code>---</code> is just a convention and I wouldn't pay too much attention to it. If it makes your work more convenient, you can use it.</p>

<p>As to your additional question in the comment:</p>

<blockquote>
  <p>I'm curious if having two load balancers would also work as well or
  if Ingress is suited better for this scenario?</p>
</blockquote>

<p>I hope after reading the whole answer it's already much clearer. Note that typically an <code>Ingress</code> also uses <strong>loadbalancer</strong> under the hood. If you only want to expose externally your <strong>frontend app</strong> without using different paths which are backed by separate <strong>microservices</strong>, you may not even need an <code>Ingress</code>. <a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer" rel="nofollow noreferrer">LoadBalancer</a> <code>Service</code> would be totally enough for what you want to accomplish. Remember that you also use it to expose your app to the external world. If you expose something only within your cluster, that shouldn't be reachable from outside, use simple <code>ClusterIP</code> <code>Service</code> instead.</p>

<blockquote>
  <p>LoadBalancer: Exposes the Service externally using a cloud provider’s
  load balancer. NodePort and ClusterIP Services, to which the external
  load balancer routes, are automatically created.</p>
</blockquote>

<p>I hope this answered your question.</p>
