<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Celso Nery</title>
    <description>The latest articles on DEV Community by Celso Nery (@celsonery).</description>
    <link>https://dev.to/celsonery</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F416745%2F74d78e44-1418-4d26-89f1-06099837bf0d.jpg</url>
      <title>DEV Community: Celso Nery</title>
      <link>https://dev.to/celsonery</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/celsonery"/>
    <language>en</language>
    <item>
      <title>Minecraft Server - Part 3: Running on Kubernetes</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:20:55 +0000</pubDate>
      <link>https://dev.to/celsonery/minecraft-server-part-3-running-on-kubernetes-4fkf</link>
      <guid>https://dev.to/celsonery/minecraft-server-part-3-running-on-kubernetes-4fkf</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/servidor-minecraft-parte-3-rodando-no-kubernetes-208c"&gt;Versão em português&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Minecraft Server - Part 3: Running on Kubernetes
&lt;/h1&gt;

&lt;p&gt;In Part 2 of this series, we got the Minecraft server running in Docker containers, with persistence via volumes and automatic restart. In this article, will bringing the same server into a &lt;strong&gt;Kubernetes cluster&lt;/strong&gt;, gaining managed storage via &lt;code&gt;PersistentVolumeClaim&lt;/code&gt;, isolation via &lt;code&gt;Namespace&lt;/code&gt;, and the flexibility to run on any available node in the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minecraft Bedrock on Kubernetes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-pvc&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-server&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-bedrock-server:latest&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19132&lt;/span&gt;
              &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UDP&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EULA&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GAMEMODE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;survival"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MAX_PLAYERS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MOTD&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bedrock&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Server!"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OPS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_username"&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-data&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-data&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-pvc&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bedrock-udp&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19132&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19132&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UDP&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the structure, which brings together several concepts already covered throughout the series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Namespace&lt;/strong&gt; (&lt;code&gt;minecraft-br&lt;/code&gt;): isolates the Minecraft Bedrock resources from the rest of the cluster;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PersistentVolumeClaim&lt;/strong&gt; (10Gi): ensures the saved world survives pod restarts and recreations, without it, every new pod would start with an empty world;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: runs a single replica (&lt;code&gt;replicas: 1&lt;/code&gt;), multiple replicas of the same Minecraft world &lt;strong&gt;don't work&lt;/strong&gt;, since the game wasn't designed for multiple instances accessing the same save simultaneously;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;LoadBalancer&lt;/code&gt;-type Service&lt;/strong&gt;, on UDP port &lt;code&gt;19132&lt;/code&gt;, exposing the server outside the cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;On on-premise clusters, the &lt;code&gt;LoadBalancer&lt;/code&gt; type usually doesn't provision an IP automatically (that's a native cloud provider feature), you need a controller like &lt;strong&gt;MetalLB&lt;/strong&gt; for the Service to actually receive a usable external IP. Without it, the Service's external IP will stay &lt;code&gt;&amp;lt;pending&amp;gt;&lt;/code&gt; indefinitely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Minecraft Java on Kubernetes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-pvc&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-server&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server:latest&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25565&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EULA&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MEMORY&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1G"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VERSION&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latest"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MAX_PLAYERS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MOTD&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;server"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ONLINE_MODE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WHITELIST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OPS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_username"&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-data&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-data&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-pvc&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mc-tcp&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25565&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25565&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike Bedrock, here the &lt;code&gt;containerPort&lt;/code&gt; and Service ports use &lt;strong&gt;TCP&lt;/strong&gt; (the default, when &lt;code&gt;protocol&lt;/code&gt; isn't specified on the container, but made explicit on the Service for clarity), consistent with Minecraft Java communicating over TCP, as we saw in Part 2.&lt;/p&gt;

&lt;p&gt;Some environment fields specific to this image:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MEMORY&lt;/code&gt;: sets the memory limit passed to the JVM internally by the image (equivalent to the &lt;code&gt;-Xmx&lt;/code&gt; flag seen in the bare metal installation);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VERSION&lt;/code&gt;: lets you pin a specific Minecraft version (for example, &lt;code&gt;"1.20.4"&lt;/code&gt;) instead of always using the latest;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ONLINE_MODE&lt;/code&gt;: when set to &lt;code&gt;"TRUE"&lt;/code&gt;, requires players to be authenticated with a valid Microsoft/Mojang account, only disable this if you know exactly why you need to (usually for servers with pirated clients, which carries security and legal implications).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Applying the manifests
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; minecraft-bedrock.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; minecraft-java.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checking whether the pods came up correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-br get pods

and

kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-java get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following the startup logs (the first start downloads the server files, which can take a few minutes):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-java logs &lt;span class="nt"&gt;-f&lt;/span&gt; deployment/minecraft-server

and 

kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-br logs &lt;span class="nt"&gt;-f&lt;/span&gt; deployment/minecraft-bedrock-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Series wrap-up
&lt;/h2&gt;

&lt;p&gt;Throughout this series, we saw the same Minecraft server through three stages: manual bare metal installation, containerization with Docker, and finally orchestration on a Kubernetes cluster. Each stage solved a limitation of the previous one, from manual process management, through persistence and automatic restart, to managed storage and independence from a single physical host.&lt;/p&gt;

&lt;p&gt;It's worth reinforcing an important point that applies to all three approaches: since this is a stateful game (the saved "world"), &lt;strong&gt;it's not possible to scale horizontally&lt;/strong&gt; by running multiple replicas of the same server, unlike a stateless API, Minecraft needs a single, consistent instance accessing the data volume at a time.&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>devops</category>
    </item>
    <item>
      <title>Minecraft Server - Part 2: Running with Docker</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:20:12 +0000</pubDate>
      <link>https://dev.to/celsonery/minecraft-server-part-2-running-with-docker-17bb</link>
      <guid>https://dev.to/celsonery/minecraft-server-part-2-running-with-docker-17bb</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/servidor-minecraft-parte-2-rodando-com-docker-3ai0"&gt;Versão em português&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Minecraft Server - Part 2: Running with Docker
&lt;/h1&gt;

&lt;p&gt;In Part 1 of this series, we installed the Minecraft server (Bedrock and Java) directly on the operating system, manually managing the process with &lt;code&gt;screen&lt;/code&gt;/&lt;code&gt;tmux&lt;/code&gt;. In this article, we take a natural next step: running the same server in a &lt;strong&gt;Docker container&lt;/strong&gt;, using the community-maintained images from &lt;a href="https://github.com/itzg/docker-minecraft-server" rel="noopener noreferrer"&gt;itzg/docker-minecraft-server&lt;/a&gt; and &lt;a href="https://github.com/itzg/docker-minecraft-bedrock-server" rel="noopener noreferrer"&gt;itzg/docker-minecraft-bedrock-server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Advantages over the bare metal installation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic restart&lt;/strong&gt; on failure (&lt;code&gt;restart: unless-stopped&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolated and explicit data persistence&lt;/strong&gt;, via volumes;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative configuration&lt;/strong&gt;, in a single versionable file;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation&lt;/strong&gt; of the process from the rest of the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Prerequisite: Docker and Docker Compose must already be installed. If you haven't installed them yet, please do so. If you're not sure how, check out my "Docker for Developers" series; in Part 1, I show how to install Docker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Running Minecraft Bedrock with Docker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-bedrock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-bedrock-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-server&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;19132:19132/udp"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
      &lt;span class="na"&gt;GAMEMODE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;survival"&lt;/span&gt;
      &lt;span class="na"&gt;MAX_PLAYERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
      &lt;span class="na"&gt;MOTD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bedrock&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Server!"&lt;/span&gt;
      &lt;span class="na"&gt;WHITELIST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;OPS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_username"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-data:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-bedrock-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ports: "19132:19132/udp"&lt;/code&gt;: &lt;strong&gt;Bedrock uses UDP&lt;/strong&gt;, unlike most network services, notice the explicit &lt;code&gt;/udp&lt;/code&gt; suffix;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EULA: "TRUE"&lt;/code&gt;: automatically accepts the Minecraft license, skipping the manual &lt;code&gt;eula.txt&lt;/code&gt; step seen in Part 1;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OPS&lt;/code&gt;: already grants operator permission to the given user on first startup;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minecraft-bedrock-data&lt;/code&gt;: a named volume, ensuring the world and settings survive container updates and recreations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Running Minecraft Java with Docker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-java&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java-server&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;25565:25565"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
      &lt;span class="na"&gt;GAMEMODE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;survival"&lt;/span&gt;
      &lt;span class="na"&gt;MAX_PLAYERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
      &lt;span class="na"&gt;MOTD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Java&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Server!"&lt;/span&gt;
      &lt;span class="na"&gt;WHITELIST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;OPS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_username"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minecraft-java-data:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-java-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; unlike Bedrock, &lt;strong&gt;Minecraft Java uses TCP&lt;/strong&gt;, not UDP, the port should be mapped as &lt;code&gt;"25565:25565"&lt;/code&gt; (TCP is Docker's default protocol when none is specified), without the &lt;code&gt;/udp&lt;/code&gt; suffix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bringing up the servers
&lt;/h2&gt;

&lt;p&gt;Each server can live in its own &lt;code&gt;docker-compose.yaml&lt;/code&gt; file (recommended, so you can manage them independently) or both in the same file, as two separate services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following the startup logs (the first start can take a few minutes, downloading the server files):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Managing the server via console
&lt;/h2&gt;

&lt;p&gt;The itzg images include a built-in RCON tool (&lt;code&gt;rcon-cli&lt;/code&gt;) inside the container, letting you run server commands without needing to attach directly to the process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; minecraft-java-server rcon-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the RCON console, the same commands from Part 1 work normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;whitelist add new_player
op new_player
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Bedrock, the container also accepts commands via &lt;code&gt;send-command&lt;/code&gt; (depending on the image version) or directly through the &lt;code&gt;WHITELIST&lt;/code&gt; and &lt;code&gt;OPS&lt;/code&gt; environment variables in &lt;code&gt;docker-compose.yaml&lt;/code&gt;, restarting the container to apply changes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The itzg images have a large number of available environment variables (difficulty, world type, plugins, mods, etc.), it's worth checking each image's official documentation on Docker Hub for the complete, up-to-date list, since new options are added frequently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/r/itzg/minecraft-server" rel="noopener noreferrer"&gt;Docker Hub itzg repository&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;With Minecraft running in Docker containers, we now have automatic restart, persistence, and declarative configuration. But this still runs on a single host, if the machine goes down, the server goes down with it. In &lt;strong&gt;Part 3&lt;/strong&gt; of this series, we'll take the same server into a &lt;strong&gt;Kubernetes&lt;/strong&gt; cluster, gaining features like managed storage via PersistentVolumeClaim and the ability to run on any available node in the cluster.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continued in Part 3.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>devops</category>
    </item>
    <item>
      <title>Minecraft Server - Part 1: Bare Metal Installation</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:19:02 +0000</pubDate>
      <link>https://dev.to/celsonery/minecraft-server-part-1-bare-metal-installation-1dno</link>
      <guid>https://dev.to/celsonery/minecraft-server-part-1-bare-metal-installation-1dno</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/servidor-minecraft-parte-1-instalacao-bare-metal-3g2d"&gt;Versão em português&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Minecraft Server - Part 1: Bare Metal Installation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Running your own Minecraft server gives you full control over the game, mods, rules, a persistent world, and no dependency on third-party servers. This is the first part of a series that will provide three installation options: we start here with a &lt;strong&gt;bare metal&lt;/strong&gt; installation (directly on the operating system), then move on to &lt;strong&gt;Docker&lt;/strong&gt;, and finally to &lt;strong&gt;Kubernetes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are two main editions of the game, with incompatible servers between them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bedrock Edition&lt;/strong&gt;: cross-platform (Windows, consoles, mobile), uses the UDP protocol;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java Edition&lt;/strong&gt;: the "classic" PC version, with the largest ecosystem of mods and plugins, uses the TCP protocol.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will cover the installing of both.&lt;/p&gt;

&lt;h2&gt;
  
  
  System requirements
&lt;/h2&gt;

&lt;p&gt;Requirements vary mainly with the number of simultaneous players and whether the world uses heavy mods/plugins:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Players&lt;/th&gt;
&lt;th&gt;Recommended RAM&lt;/th&gt;
&lt;th&gt;CPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1-5&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;2 cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-10&lt;/td&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;td&gt;2-4 cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10-20+&lt;/td&gt;
&lt;td&gt;8GB+&lt;/td&gt;
&lt;td&gt;4+ cores&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The Java edition tends to consume more resources than Bedrock for the same number of players, especially with plugins like Spigot/Paper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Installing the Minecraft Bedrock Server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Download
&lt;/h3&gt;

&lt;p&gt;Download the official Bedrock server package for Linux directly from the official page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.minecraft.net/en-us/download/server/bedrock" rel="noopener noreferrer"&gt;minecraft.net/download/server/bedrock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg5cexzt1wpbis3u5pcti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg5cexzt1wpbis3u5pcti.png" alt="Minecraft Bedrock Server download page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After downloading, extract the &lt;code&gt;.zip&lt;/code&gt; file into a dedicated directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/minecraft-bedrock
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/minecraft-bedrock
unzip bedrock-server-&lt;span class="k"&gt;*&lt;/span&gt;.zip
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x bedrock_server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LD_LIBRARY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; ./bedrock_server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The Bedrock server relies on shared libraries in its own directory, that's why the &lt;code&gt;LD_LIBRARY_PATH=.&lt;/code&gt; variable is needed for it to find them correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To keep the server running even after closing the terminal, use &lt;code&gt;screen&lt;/code&gt; or &lt;code&gt;tmux&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;screen &lt;span class="nt"&gt;-S&lt;/span&gt; minecraft-bedrock
&lt;span class="nv"&gt;LD_LIBRARY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; ./bedrock_server
&lt;span class="c"&gt;# Ctrl+A, D to detach without stopping the process&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring the server
&lt;/h2&gt;

&lt;p&gt;Bedrock server options live in the &lt;code&gt;server.properties&lt;/code&gt; file, automatically generated on first run. Full documentation for all available properties is on the official wiki:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://minecraft.fandom.com/wiki/Server.properties" rel="noopener noreferrer"&gt;minecraft.fandom.com/wiki/Server.properties&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some of the most commonly used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;server-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;My Bedrock Server&lt;/span&gt;
&lt;span class="py"&gt;gamemode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;survival&lt;/span&gt;
&lt;span class="py"&gt;difficulty&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;normal&lt;/span&gt;
&lt;span class="py"&gt;max-players&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
&lt;span class="py"&gt;online-mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;white-list&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;level-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Bedrock level&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After editing the file, restart the server to apply the changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Minecraft Java Server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisite: Java
&lt;/h3&gt;

&lt;p&gt;The Java server needs a JRE/JDK installed, the exact version depends on the Minecraft version (more recent versions require Java 17 or 21). To install on Debian:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openjdk-21-jre-headless
java &lt;span class="nt"&gt;-version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download
&lt;/h3&gt;

&lt;p&gt;Download the &lt;code&gt;server.jar&lt;/code&gt; for the desired version from the official Minecraft Java Server download page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.minecraft.net/en-us/download/server" rel="noopener noreferrer"&gt;www.minecraft.net/en-us/download/server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyxtc1ppk0arbqpk1qqre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyxtc1ppk0arbqpk1qqre.png" alt="Minecraft Java Server download page" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/minecraft-java
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/minecraft-java
&lt;span class="c"&gt;# Download the server.jar for the desired version into this directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Accepting the EULA
&lt;/h3&gt;

&lt;p&gt;On first run, Minecraft creates an &lt;code&gt;eula.txt&lt;/code&gt; file and refuses to start until you manually accept the terms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"eula=true"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; eula.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-Xmx2G&lt;/span&gt; &lt;span class="nt"&gt;-Xms1G&lt;/span&gt; &lt;span class="nt"&gt;-jar&lt;/span&gt; server.jar nogui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-Xmx2G&lt;/code&gt;: maximum memory the JVM can use;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Xms1G&lt;/code&gt;: initial memory allocated;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nogui&lt;/code&gt;: runs without the graphical interface, ideal for servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like with Bedrock, use &lt;code&gt;screen&lt;/code&gt; or &lt;code&gt;tmux&lt;/code&gt; to keep the process running in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing the server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Player list (whitelist)
&lt;/h3&gt;

&lt;p&gt;Restricting who can join the server is done via a whitelist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Bedrock&lt;/strong&gt;, edit &lt;code&gt;whitelist.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your_username"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And enable it in &lt;code&gt;server.properties&lt;/code&gt;: &lt;code&gt;white-list=true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Java&lt;/strong&gt;, use the server console (the terminal where it's running):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;whitelist add your_username
whitelist on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  User permissions (ops)
&lt;/h3&gt;

&lt;p&gt;Granting administrator permissions (operator commands) also differs between editions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Bedrock&lt;/strong&gt;, edit &lt;code&gt;permissions.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"operator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"xuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your_xuid"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;On Bedrock, you need the player's &lt;strong&gt;XUID&lt;/strong&gt; (Xbox Live account identifier), not just their username.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;On Java&lt;/strong&gt;, from the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;op your_username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Exposing it to the internet
&lt;/h2&gt;

&lt;p&gt;By default, the server is only accessible on the local network. To allow external connections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Open the port in the machine's firewall&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bedrock: port &lt;code&gt;19132/UDP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Java: port &lt;code&gt;25565/TCP&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set up port forwarding&lt;/strong&gt; on your router, pointing the external port to the internal IP of the machine running the server.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Setting up dynamic DNS with No-IP
&lt;/h2&gt;

&lt;p&gt;Most home internet connections have a dynamic public IP, it changes periodically, breaking access for anyone who saved the old IP. &lt;strong&gt;No-IP&lt;/strong&gt; solves this, associating a fixed domain (for example, &lt;code&gt;myserver.ddns.net&lt;/code&gt;) with your current IP, updated automatically.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a free account at &lt;a href="https://www.noip.com/" rel="noopener noreferrer"&gt;noip.com&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Register a hostname (for example, &lt;code&gt;my-minecraft.ddns.net&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;Install the &lt;strong&gt;DUC (Dynamic Update Client)&lt;/strong&gt; on your server or router (many routers already have native No-IP support in their dynamic DNS settings);&lt;/li&gt;
&lt;li&gt;Share the hostname with your friends instead of the IP, it will keep working even when your IP changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;With the server running bare metal, manually managed with &lt;code&gt;screen&lt;/code&gt;/&lt;code&gt;tmux&lt;/code&gt;, you can already play with friends. But this model has limitations: no isolation, no automatic restart on failure, and manual configuration from scratch if you need to migrate to another machine. In &lt;strong&gt;Part 2&lt;/strong&gt; of this series, we'll run the same server in a &lt;strong&gt;Docker&lt;/strong&gt; container, solving these problems with a declarative and reproducible configuration.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continued in Part 2.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>devops</category>
    </item>
    <item>
      <title>Servidor Minecraft - Parte 3: Rodando no Kubernetes</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:17:17 +0000</pubDate>
      <link>https://dev.to/celsonery/servidor-minecraft-parte-3-rodando-no-kubernetes-208c</link>
      <guid>https://dev.to/celsonery/servidor-minecraft-parte-3-rodando-no-kubernetes-208c</guid>
      <description>&lt;p&gt;🇺🇸 &lt;a href=""&gt;English version comming soon&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Servidor Minecraft - Parte 3: Rodando no Kubernetes
&lt;/h1&gt;

&lt;p&gt;Na Parte 2 desta série, colocamos o servidor Minecraft para rodar em containers Docker, com persistência via volumes e reinício automático. Neste artigo, vamos levar o mesmo servidor para dentro de um &lt;strong&gt;cluster Kubernetes&lt;/strong&gt;, ganhando armazenamento gerenciado via &lt;code&gt;PersistentVolumeClaim&lt;/code&gt;, isolamento por &lt;code&gt;Namespace&lt;/code&gt; e a flexibilidade de rodar em qualquer nó disponível do cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minecraft Bedrock no Kubernetes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-pvc&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-server&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-bedrock-server:latest&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19132&lt;/span&gt;
              &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UDP&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EULA&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GAMEMODE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;survival"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MAX_PLAYERS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MOTD&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Servidor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Bedrock&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft!"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OPS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seu_username"&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-data&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-data&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-pvc&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-br&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bedrock-udp&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19132&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;19132&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UDP&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare na estrutura, que junta vários conceitos já vistos ao longo da série:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Namespace&lt;/strong&gt; (&lt;code&gt;minecraft-br&lt;/code&gt;): isola os recursos do Minecraft Bedrock do restante do cluster;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PersistentVolumeClaim&lt;/strong&gt; (10Gi): garante que o mundo salvo sobreviva a reinicializações e recriações do pod, sem isso, cada novo pod começaria com um mundo vazio;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: roda uma única réplica (&lt;code&gt;replicas: 1&lt;/code&gt;), múltiplas réplicas de um mesmo mundo Minecraft &lt;strong&gt;não funcionam&lt;/strong&gt;, já que o jogo não foi projetado para múltiplas instâncias acessando o mesmo save simultaneamente;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service do tipo &lt;code&gt;LoadBalancer&lt;/code&gt;&lt;/strong&gt;, na porta UDP &lt;code&gt;19132&lt;/code&gt;, expondo o servidor para fora do cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Em clusters on-premise, o tipo &lt;code&gt;LoadBalancer&lt;/code&gt; normalmente não provisiona um IP automaticamente (isso é um recurso nativo de provedores de nuvem), é necessário um controlador como o &lt;strong&gt;MetalLB&lt;/strong&gt; para que o Service realmente receba um IP externo utilizável. Sem isso, o Service ficará com o IP externo em estado &lt;code&gt;&amp;lt;pending&amp;gt;&lt;/code&gt; indefinidamente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Minecraft Java no Kubernetes
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-pvc&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessModes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ReadWriteOnce&lt;/span&gt;
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10Gi&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-server&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server:latest&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25565&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EULA&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MEMORY&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1G"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;VERSION&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latest"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MAX_PLAYERS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;MOTD&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bem-vindo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ao&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;servidor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ONLINE_MODE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WHITELIST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OPS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seu_username"&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/data&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-data&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-data&lt;/span&gt;
          &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-pvc&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-service&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mc-tcp&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25565&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25565&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diferente do Bedrock, aqui a porta do &lt;code&gt;containerPort&lt;/code&gt; e do Service usam &lt;strong&gt;TCP&lt;/strong&gt; (o padrão, quando &lt;code&gt;protocol&lt;/code&gt; não é especificado no container, mas explicitado no Service para clareza), coerente com o fato de o Minecraft Java se comunicar via TCP, como vimos na Parte 2.&lt;/p&gt;

&lt;p&gt;Alguns campos de ambiente específicos dessa imagem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MEMORY&lt;/code&gt;: define o limite de memória passado para a JVM internamente pela imagem (equivalente ao &lt;code&gt;-Xmx&lt;/code&gt; visto na instalação bare metal);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VERSION&lt;/code&gt;: permite fixar uma versão específica do Minecraft (por exemplo, &lt;code&gt;"1.20.4"&lt;/code&gt;) em vez de sempre usar a mais recente;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ONLINE_MODE&lt;/code&gt;: quando &lt;code&gt;"TRUE"&lt;/code&gt;, exige que os jogadores estejam autenticados com uma conta Microsoft/Mojang válida, desative apenas se souber exatamente por que precisa (geralmente para servidores com clientes piratas, o que tem implicações de segurança e legalidade).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Aplicando os manifestos
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; minecraft-bedrock.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; minecraft-java.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verificando se os pods subiram corretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-br get po

e

kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-java get po
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acompanhando os logs de inicialização (o primeiro start baixa os arquivos do servidor, podendo levar alguns minutos):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-java logs &lt;span class="nt"&gt;-f&lt;/span&gt; deploy/minecraft-server

e

kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; minecraft-br logs &lt;span class="nt"&gt;-f&lt;/span&gt; deploy/minecraft-bedrock-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Considerações finais da série
&lt;/h2&gt;

&lt;p&gt;Ao longo desta série, vimos o mesmo servidor Minecraft por três estágios: instalação manual bare metal, containerização com Docker, e por fim orquestração em um cluster Kubernetes. Cada estágio resolveu uma limitação do anterior, do gerenciamento manual de processos, passando por persistência e reinício automático, até chegar em armazenamento gerenciado e independência de um único host físico.&lt;/p&gt;

&lt;p&gt;Vale reforçar um ponto importante que se aplica às três abordagens: por se tratar de um jogo com estado (o "mundo" salvo), &lt;strong&gt;não é possível escalar horizontalmente&lt;/strong&gt; rodando múltiplas réplicas do mesmo servidor, diferente de uma API stateless, o Minecraft precisa de uma única instância consistente acessando o volume de dados por vez.&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>devops</category>
    </item>
    <item>
      <title>Servidor Minecraft - Parte 2: Rodando com Docker</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:16:02 +0000</pubDate>
      <link>https://dev.to/celsonery/servidor-minecraft-parte-2-rodando-com-docker-3ai0</link>
      <guid>https://dev.to/celsonery/servidor-minecraft-parte-2-rodando-com-docker-3ai0</guid>
      <description>&lt;p&gt;🇺🇸 &lt;a href=""&gt;English version comming soon&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Servidor Minecraft - Parte 2: Rodando com Docker
&lt;/h1&gt;

&lt;p&gt;Na Parte 1 desta série, instalamos o servidor Minecraft (Bedrock e Java) diretamente no sistema operacional, gerenciando o processo manualmente com &lt;code&gt;screen&lt;/code&gt;/&lt;code&gt;tmux&lt;/code&gt;. Neste artigo, damos um passo natural adiante: rodar o mesmo servidor em um &lt;strong&gt;container Docker&lt;/strong&gt;, usando as imagens mantidas pela comunidade do projeto &lt;a href="https://github.com/itzg/docker-minecraft-server" rel="noopener noreferrer"&gt;itzg/docker-minecraft-server&lt;/a&gt; e &lt;a href="https://github.com/itzg/docker-minecraft-bedrock-server" rel="noopener noreferrer"&gt;itzg/docker-minecraft-bedrock-server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As vantagens em relação à instalação bare metal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reinício automático&lt;/strong&gt; em caso de falha (&lt;code&gt;restart: unless-stopped&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistência de dados&lt;/strong&gt; isolada e explícita, via volumes;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuração declarativa&lt;/strong&gt;, em um único arquivo versionável;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolamento&lt;/strong&gt; do processo do restante do sistema.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Pré-requisito: Docker e Docker Compose já instalados. Se ainda não tiver, instale. Se não souber como, veja a minha série "Docker para desenvolvedores", la mostro na parte 1 como instalar o docker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rodando o Minecraft Bedrock com Docker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-bedrock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-bedrock-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-server&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;19132:19132/udp"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
      &lt;span class="na"&gt;GAMEMODE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;survival"&lt;/span&gt;
      &lt;span class="na"&gt;MAX_PLAYERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
      &lt;span class="na"&gt;MOTD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Servidor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Bedrock&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft!"&lt;/span&gt;
      &lt;span class="na"&gt;WHITELIST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;OPS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seu_username"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minecraft-bedrock-data:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-bedrock-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pontos importantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ports: "19132:19132/udp"&lt;/code&gt;: o &lt;strong&gt;Bedrock usa UDP&lt;/strong&gt;, diferente da maioria dos serviços de rede, repare no sufixo &lt;code&gt;/udp&lt;/code&gt; explícito;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EULA: "TRUE"&lt;/code&gt;: aceita automaticamente a licença do Minecraft, evitando a etapa manual do &lt;code&gt;eula.txt&lt;/code&gt; vista na Parte 1;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OPS&lt;/code&gt;: já concede permissão de operador ao usuário informado, na primeira inicialização;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minecraft-bedrock-data&lt;/code&gt;: volume nomeado, garantindo que o mundo e as configurações sobrevivam a atualizações e recriações do container.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Rodando o Minecraft Java com Docker
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-java&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;itzg/minecraft-server:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minecraft-java-server&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;25565:25565"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TRUE"&lt;/span&gt;
      &lt;span class="na"&gt;GAMEMODE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;survival"&lt;/span&gt;
      &lt;span class="na"&gt;MAX_PLAYERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
      &lt;span class="na"&gt;MOTD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Servidor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Java&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Minecraft!"&lt;/span&gt;
      &lt;span class="na"&gt;WHITELIST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
      &lt;span class="na"&gt;OPS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seu_username"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;minecraft-java-data:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minecraft-java-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Importante:&lt;/strong&gt; diferente do Bedrock, o &lt;strong&gt;Minecraft Java usa TCP&lt;/strong&gt;, não UDP, a porta deve ser mapeada como &lt;code&gt;"25565:25565"&lt;/code&gt; (TCP é o protocolo padrão do Docker quando nenhum é especificado), sem o sufixo &lt;code&gt;/udp&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Subindo os servidores
&lt;/h2&gt;

&lt;p&gt;Cada servidor pode ficar em seu próprio arquivo &lt;code&gt;docker-compose.yaml&lt;/code&gt; (recomendado, para gerenciá-los de forma independente) ou ambos no mesmo arquivo, como dois serviços distintos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acompanhando os logs de inicialização (o primeiro start pode demorar alguns minutos, baixando os arquivos do servidor):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Gerenciando o servidor via console
&lt;/h2&gt;

&lt;p&gt;As imagens do itzg incluem uma ferramenta de RCON (&lt;code&gt;rcon-cli&lt;/code&gt;) embutida no container, permitindo executar comandos do servidor sem precisar anexar ao processo diretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; minecraft-java-server rcon-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro do RCON, os mesmos comandos vistos na Parte 1 funcionam normalmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;whitelist add novo_jogador
op novo_jogador
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para o Bedrock, o container também aceita comandos via &lt;code&gt;send-command&lt;/code&gt; (dependendo da versão da imagem) ou diretamente pelas variáveis de ambiente &lt;code&gt;WHITELIST&lt;/code&gt; e &lt;code&gt;OPS&lt;/code&gt; no &lt;code&gt;docker-compose.yaml&lt;/code&gt;, reiniciando o container para aplicar mudanças.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As imagens do itzg têm uma quantidade grande de variáveis de ambiente disponíveis (dificuldade, tipo de mundo, plugins, mods, etc.), vale consultar a documentação oficial de cada imagem no Docker Hub para a lista completa e atualizada, já que novas opções são adicionadas com frequência.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://hub.docker.com/r/itzg/minecraft-server" rel="noopener noreferrer"&gt;Repositório itzg no Docker Hub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Próximos passos
&lt;/h2&gt;

&lt;p&gt;Com o Minecraft rodando em containers Docker, já temos reinício automático, persistência e configuração declarativa. Mas isso ainda roda em um único host, se a máquina cair, o servidor cai junto. Na &lt;strong&gt;Parte 3&lt;/strong&gt; desta série, vamos levar o mesmo servidor para dentro de um cluster &lt;strong&gt;Kubernetes&lt;/strong&gt;, ganhando recursos como armazenamento gerenciado via PersistentVolumeClaim e a possibilidade de rodar em qualquer nó disponível do cluster.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continua na Parte 3.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>devops</category>
    </item>
    <item>
      <title>Servidor Minecraft - Parte 1: Instalação Bare Metal</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:15:05 +0000</pubDate>
      <link>https://dev.to/celsonery/servidor-minecraft-parte-1-instalacao-bare-metal-3g2d</link>
      <guid>https://dev.to/celsonery/servidor-minecraft-parte-1-instalacao-bare-metal-3g2d</guid>
      <description>&lt;p&gt;🇺🇸 &lt;a href=""&gt;English version comming soon&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Servidor Minecraft - Parte 1: Instalação Bare Metal
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Rodar seu próprio servidor de Minecraft dá controle total sobre o jogo, mods, regras, mundo persistente, e nenhuma dependência de servidores de terceiros. Esta é a primeira parte de uma série que dará 3 opções de instalação: começamos aqui com a instalação &lt;strong&gt;bare metal&lt;/strong&gt; (direto no sistema operacional), depois avançamos para &lt;strong&gt;Docker&lt;/strong&gt; e, por fim, para &lt;strong&gt;Kubernetes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Existem duas versões principais do jogo, com servidores incompatíveis entre si:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bedrock Edition&lt;/strong&gt;: multiplataforma (Windows, consoles, celular), usa o protocolo UDP;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Java Edition&lt;/strong&gt;: a versão "clássica" para PC, com o maior ecossistema de mods e plugins, usa o protocolo TCP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vou cobrir a instalação de ambas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requisitos do sistema
&lt;/h2&gt;

&lt;p&gt;Os requisitos variam principalmente com o número de jogadores simultâneos e se o mundo usa mods/plugins pesados:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Jogadores&lt;/th&gt;
&lt;th&gt;RAM recomendada&lt;/th&gt;
&lt;th&gt;CPU&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1-5&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;2 cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-10&lt;/td&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;td&gt;2-4 cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10-20+&lt;/td&gt;
&lt;td&gt;8GB+&lt;/td&gt;
&lt;td&gt;4+ cores&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;A versão Java tende a consumir mais recursos que a Bedrock para o mesmo número de jogadores, especialmente com plugins como Spigot/Paper.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Instalando o Minecraft Bedrock Server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Download
&lt;/h3&gt;

&lt;p&gt;Baixe o pacote oficial do servidor Bedrock para Linux diretamente da página oficial:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.minecraft.net/en-us/download/server/bedrock" rel="noopener noreferrer"&gt;minecraft.net/download/server/bedrock&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg5cexzt1wpbis3u5pcti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg5cexzt1wpbis3u5pcti.png" alt="Minecraft Bedrock Server download page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após o download, extraia o arquivo &lt;code&gt;.zip&lt;/code&gt; em um diretório dedicado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/minecraft-bedrock
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/minecraft-bedrock
unzip bedrock-server-&lt;span class="k"&gt;*&lt;/span&gt;.zip
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x bedrock_server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rodando o servidor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LD_LIBRARY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; ./bedrock_server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;O servidor Bedrock depende de bibliotecas compartilhadas no próprio diretório, por isso a variável &lt;code&gt;LD_LIBRARY_PATH=.&lt;/code&gt; é necessária para ele encontrá-las corretamente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para manter o servidor rodando mesmo após fechar o terminal, use &lt;code&gt;screen&lt;/code&gt; ou &lt;code&gt;tmux&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;screen &lt;span class="nt"&gt;-S&lt;/span&gt; minecraft-bedrock
&lt;span class="nv"&gt;LD_LIBRARY_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; ./bedrock_server
&lt;span class="c"&gt;# Ctrl+A, D para sair sem encerrar o processo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configurando o servidor
&lt;/h2&gt;

&lt;p&gt;As opções do servidor Bedrock ficam no arquivo &lt;code&gt;server.properties&lt;/code&gt;, gerado automaticamente na primeira execução. A documentação completa de todas as propriedades disponíveis está na wiki oficial:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://minecraft.fandom.com/wiki/Server.properties" rel="noopener noreferrer"&gt;minecraft.fandom.com/wiki/Server.properties&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Algumas das mais usadas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;server-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Meu Servidor Bedrock&lt;/span&gt;
&lt;span class="py"&gt;gamemode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;survival&lt;/span&gt;
&lt;span class="py"&gt;difficulty&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;normal&lt;/span&gt;
&lt;span class="py"&gt;max-players&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
&lt;span class="py"&gt;online-mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;white-list&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;false&lt;/span&gt;
&lt;span class="py"&gt;level-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Bedrock level&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Após alterar o arquivo, reinicie o servidor para aplicar as mudanças.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalando o Minecraft Java Server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pré-requisito: Java
&lt;/h3&gt;

&lt;p&gt;O servidor Java precisa de uma JRE/JDK instalada, a versão exata depende da versão do Minecraft (versões mais recentes exigem Java 17 ou 21). Para instalar no Debian:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;openjdk-21-jre-headless
java &lt;span class="nt"&gt;-version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download
&lt;/h3&gt;

&lt;p&gt;Baixe o &lt;code&gt;server.jar&lt;/code&gt; da versão desejada na página oficial de downloads do Minecraft Java Server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.minecraft.net/en-us/download/server" rel="noopener noreferrer"&gt;www.minecraft.net/en-us/download/server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyxtc1ppk0arbqpk1qqre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyxtc1ppk0arbqpk1qqre.png" alt="Minecraft Java Server download page" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/minecraft-java
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/minecraft-java
&lt;span class="c"&gt;# Baixe o server.jar correspondente à versão desejada para este diretório&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Aceitando a EULA
&lt;/h3&gt;

&lt;p&gt;Na primeira execução, o Minecraft cria um arquivo &lt;code&gt;eula.txt&lt;/code&gt; e recusa iniciar até que você aceite os termos manualmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"eula=true"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; eula.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rodando o servidor
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-Xmx2G&lt;/span&gt; &lt;span class="nt"&gt;-Xms1G&lt;/span&gt; &lt;span class="nt"&gt;-jar&lt;/span&gt; server.jar nogui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-Xmx2G&lt;/code&gt;: memória máxima que a JVM pode usar;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Xms1G&lt;/code&gt;: memória inicial alocada;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nogui&lt;/code&gt;: roda sem a interface gráfica, ideal para servidores.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assim como no Bedrock, use &lt;code&gt;screen&lt;/code&gt; ou &lt;code&gt;tmux&lt;/code&gt; para manter o processo rodando em segundo plano.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gerenciando o servidor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lista de usuários (whitelist)
&lt;/h3&gt;

&lt;p&gt;Restringir quem pode entrar no servidor é feito via whitelist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Bedrock&lt;/strong&gt;, edite &lt;code&gt;whitelist.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"seu_username"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E habilite no &lt;code&gt;server.properties&lt;/code&gt;: &lt;code&gt;white-list=true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Java&lt;/strong&gt;, use o console do servidor (o terminal onde ele está rodando):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;whitelist add seu_username
whitelist on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Permissões de usuários (ops)
&lt;/h3&gt;

&lt;p&gt;Dar permissões de administrador (comandos de operador) também difere entre as versões.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Bedrock&lt;/strong&gt;, edite &lt;code&gt;permissions.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"operator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"xuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"seu_xuid"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;No Bedrock, é necessário o &lt;strong&gt;XUID&lt;/strong&gt; do jogador (identificador da conta Xbox Live), não apenas o nome de usuário.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;No Java&lt;/strong&gt;, pelo console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;op seu_username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Expondo para a internet
&lt;/h2&gt;

&lt;p&gt;Por padrão, o servidor só é acessível na rede local. Para permitir conexões externas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Libere a porta no firewall&lt;/strong&gt; da própria máquina:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bedrock: porta &lt;code&gt;19132/UDP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Java: porta &lt;code&gt;25565/TCP&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure o redirecionamento de porta (port forward)&lt;/strong&gt; no seu roteador, apontando a porta externa para o IP interno da máquina que roda o servidor.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Criando um DNS dinâmico com No-IP
&lt;/h2&gt;

&lt;p&gt;A maioria das conexões residenciais tem IP público dinâmico, ele muda periodicamente, quebrando o acesso de quem salvou o IP antigo. O &lt;strong&gt;No-IP&lt;/strong&gt; resolve isso, associando um domínio fixo (por exemplo, &lt;code&gt;meuservidor.ddns.net&lt;/code&gt;) ao seu IP atual, atualizado automaticamente.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Crie uma conta gratuita em &lt;a href="https://www.noip.com/" rel="noopener noreferrer"&gt;noip.com&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Registre um hostname (por exemplo, &lt;code&gt;meu-minecraft.ddns.net&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;Instale o cliente &lt;strong&gt;DUC (Dynamic Update Client)&lt;/strong&gt; no seu servidor ou roteador (muitos roteadores já têm suporte nativo a No-IP nas configurações de DNS dinâmico);&lt;/li&gt;
&lt;li&gt;Compartilhe o hostname com seus amigos em vez do IP, ele continuará funcionando mesmo quando seu IP mudar.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Próximos passos
&lt;/h2&gt;

&lt;p&gt;Com o servidor rodando bare metal, gerenciado manualmente com &lt;code&gt;screen&lt;/code&gt;/&lt;code&gt;tmux&lt;/code&gt;, já é possível jogar com amigos. Mas esse modelo tem limitações: sem isolamento, sem reinício automático em caso de falha, e configuração manual do zero se precisar migrar de máquina. Na &lt;strong&gt;Parte 2&lt;/strong&gt; desta série, vamos rodar o mesmo servidor em um container &lt;strong&gt;Docker&lt;/strong&gt;, resolvendo esses problemas com uma configuração declarativa e reprodutível.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continua na Parte 2.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>minecraft</category>
      <category>linux</category>
      <category>selfhosted</category>
      <category>devops</category>
    </item>
    <item>
      <title>Building an On-Premise Kubernetes Cluster - Part 7: Essential Production Features</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Wed, 19 Aug 2026 14:15:12 +0000</pubDate>
      <link>https://dev.to/celsonery/building-an-on-premise-kubernetes-cluster-part-7-essential-production-features-446i</link>
      <guid>https://dev.to/celsonery/building-an-on-premise-kubernetes-cluster-part-7-essential-production-features-446i</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/montando-um-cluster-kubernetes-on-premise-parte-7-recursos-essenciais-para-producao-5fpp"&gt;Versão em português aqui&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Building an On-Premise Kubernetes Cluster - Part 7: Essential Production Features
&lt;/h1&gt;

&lt;p&gt;In previous parts of this series, we built the cluster from scratch and learned the basic structure of YAML manifests. But there's a real gap between "a Deployment that works" and "a Deployment ready for production." In this article, I cover a set of features I consider essential for that second scenario: &lt;strong&gt;Namespaces&lt;/strong&gt;, &lt;strong&gt;Secrets&lt;/strong&gt;, private registry authentication (&lt;strong&gt;regcred&lt;/strong&gt;), &lt;strong&gt;RollingUpdate&lt;/strong&gt;, &lt;strong&gt;SecurityContext&lt;/strong&gt;, and &lt;strong&gt;Requests/Limits&lt;/strong&gt;. At the end, we bring everything together in a real, complete Deployment example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespace
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Namespace&lt;/strong&gt; is a way to logically divide a single physical cluster into multiple "virtual clusters", useful for separating environments (production, staging, development) or different applications, preventing them from growing mixed together in a single space.&lt;/p&gt;

&lt;p&gt;Creating a namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create namespace aplicacao-prod

or

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create ns aplicacao-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or via manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listing existing namespaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get namespaces

or

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get ns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, practically every object created (Deployments, Services, Secrets) can, and generally should, declare which namespace it lives in, through the &lt;code&gt;metadata.namespace&lt;/code&gt; field or using the &lt;code&gt;-n&lt;/code&gt; flag if it using by command line. This brings important benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name isolation&lt;/strong&gt;: two Deployments named &lt;code&gt;api&lt;/code&gt; can coexist peacefully, as long as they're in different namespaces;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access control (RBAC)&lt;/strong&gt;: you can restrict what a user or an application can do, scoped to a specific namespace;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization&lt;/strong&gt;: commands like &lt;code&gt;kubectl get pods -n aplicacao-prod&lt;/code&gt; make it clear what belongs to which environment or application.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't specify a namespace, Kubernetes uses the &lt;code&gt;default&lt;/code&gt; namespace, which works for quick tests, but isn't recommended for real environments where multiple applications share the cluster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Secrets
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secrets&lt;/strong&gt; store sensitive data: passwords, tokens, API keys, in a slightly more protected way than a regular ConfigMap (the content is base64-encoded, and access can be restricted via RBAC).&lt;/p&gt;

&lt;p&gt;Creating a Secret via the command line, from literal values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic aplicacao-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;aplicacao-prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mypassword &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or via a YAML manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-secret&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bXlwYXNzd29yZA==&lt;/span&gt;
  &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YWJjMTIz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Values in the &lt;code&gt;data&lt;/code&gt; field need to be &lt;strong&gt;base64&lt;/strong&gt;-encoded (&lt;code&gt;echo -n 'mypassword' | base64&lt;/code&gt;). This isn't encryption, it's just an encoding, so treat the Secret's YAML file with the same care you'd treat a plain-text password file. Never commit (Git) a Secret with real values without some additional layer of protection, like Sealed Secrets or a secrets vault (Vault).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Consuming the Secret in the application
&lt;/h3&gt;

&lt;p&gt;The most common approach is injecting the Secret's entire content as environment variables, using &lt;code&gt;envFrom&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycompany/api:1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way, every key in the Secret (&lt;code&gt;DB_PASSWORD&lt;/code&gt;, &lt;code&gt;API_KEY&lt;/code&gt;) automatically becomes an environment variable inside the container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying existing secrets
&lt;/h3&gt;

&lt;p&gt;Besides creating them, it's common to need to query secrets that already exist in the cluster, either to confirm they were created correctly, or to debug a configuration issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; get secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command lists all secrets in that namespace, showing name, type (Opaque, kubernetes.io/dockerconfigjson, etc.), and age, but it does not show their content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Describing a specific secret
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; describe secret &amp;lt;secret_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;describe&lt;/code&gt; shows more complete information about a specific secret, including which keys exist inside it (&lt;strong&gt;DB_PASSWORD&lt;/strong&gt;, &lt;strong&gt;API_KEY&lt;/strong&gt;, etc.) and the size of each value in bytes. By security design, however, describe does not decode or display the actual value of any key, it only confirms it exists and how large its content is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Viewing a secret's content
&lt;/h3&gt;

&lt;p&gt;To actually see the value of a specific key, you need to extract the field via &lt;code&gt;jsonpath&lt;/code&gt; and manually decode the base64:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; get secrets &amp;lt;secret_name&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.DB_PASSWORD}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Use this command with caution, especially on shared or recorded terminals (like logged screen/tmux sessions, or shell history saved in plain text). The decoded value appears in plain text directly in the terminal output.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Regcred - Credentials for a Private Registry
&lt;/h2&gt;

&lt;p&gt;When an application's images are stored in a private registry, whether a self-hosted registry, or a paid plan on Docker Hub or another provider, Kubernetes needs credentials to be able to pull those images when creating pods. That's what the &lt;code&gt;imagePullSecret&lt;/code&gt; is for, commonly created under the name &lt;code&gt;regcred&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The safest approach is to use a GitLab &lt;strong&gt;Deploy Token&lt;/strong&gt; (instead of your personal password), it can be scoped to read-only permission (&lt;code&gt;read_registry&lt;/code&gt;) and restricted to a specific project or group.&lt;/p&gt;

&lt;p&gt;Creating the secret with the Deploy Token:&lt;/p&gt;

&lt;p&gt;There are two ways to create this secret: via the command line (faster) or via a YAML file (more suitable when you need to version or automate its creation).&lt;/p&gt;

&lt;h4&gt;
  
  
  Option 1: creating via command line
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret docker-registry regcred &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; aplicacao-prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;registry.yourcompany.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;deploy-token-username&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;deploy-token-password&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-email@yourcompany.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n namespace&lt;/code&gt;: namespace where the secret will be created (the secret is scoped to that namespace);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--docker-server&lt;/code&gt;: private registry address;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--docker-username&lt;/code&gt; / &lt;code&gt;--docker-password&lt;/code&gt;: access credentials;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--docker-email&lt;/code&gt;: email associated with the account (required by the command, even if not always used in practice).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Option 2: creating via YAML file
&lt;/h4&gt;

&lt;p&gt;If you'd rather (or need to) version this configuration, you can manually build the secret as a YAML file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create a &lt;code&gt;config.json&lt;/code&gt; file&lt;/strong&gt; with the registry credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"auths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"registry.yourcompany.com"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;deploy-token-username&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;deploy-token-password&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-email@yourcompany.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Convert the file to base64&lt;/strong&gt;, since that's how Kubernetes expects the secret content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;config.json | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Create the &lt;code&gt;regcred.yaml&lt;/code&gt; file&lt;/strong&gt;, pasting the result of the command above into the &lt;code&gt;.dockerconfigjson&lt;/code&gt; field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;namespace&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubernetes.io/dockerconfigjson&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;.dockerconfigjson&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS5zdWFlbXByZXNhLmNvbSI6IHsKICAgICAgInVzZXJuYW1lIjogIjxkZXBsb3ktdG9rZW4tdXNlcm5hbWU+IiwKICAgICAgInBhc3N3b3JkIjogIjxkZXBsb3ktdG9rZW4tcGFzc3dvcmQ+IiwKICAgICAgImVtYWlsIjogInNldS1lbWFpbEBzdWFlbXByZXNhLmNvbSIKICAgIH0KCX0KfQo=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never commit (Git) a &lt;code&gt;regcred.yaml&lt;/code&gt; file with real credentials&lt;/strong&gt;: even though it's base64-encoded, that's not encryption, just an encoding: anyone with access to the file can decode it and recover the original password. Treat this value as a genuinely sensitive secret, using tools like Sealed Secrets, Vault, or environment variables from your CI/CD pipeline.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4. Apply the secret to the cluster:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; regcred.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using regcred in a Deployment
&lt;/h2&gt;

&lt;p&gt;Reference the secret in the Deployment through &lt;code&gt;imagePullSecrets&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.gitlab.com/organization/aplicacao:v1.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;imagePullSecrets&lt;/code&gt; field points to the &lt;code&gt;regcred&lt;/code&gt; secret created earlier, and it &lt;strong&gt;needs to be in the same namespace&lt;/strong&gt; as the Pod or Deployment that will use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  RollingUpdate
&lt;/h2&gt;

&lt;p&gt;By default, a Deployment already uses the &lt;code&gt;RollingUpdate&lt;/code&gt; strategy when updating an application's version, gradually replacing old pods with new ones, without full downtime. But the exact parameters of this process can (and should) be tuned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minReadySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;maxSurge&lt;/code&gt;&lt;/strong&gt;: how many pods &lt;strong&gt;above&lt;/strong&gt; the desired replica count can be temporarily created during the update (here, 1 extra pod);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;maxUnavailable&lt;/code&gt;&lt;/strong&gt;: how many pods can be &lt;strong&gt;unavailable&lt;/strong&gt; at the same time during the update (here, at most 1);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;minReadySeconds&lt;/code&gt;&lt;/strong&gt;: the minimum time (in seconds) a new pod needs to stay "ready" (passing health checks) before being considered available, this prevents the rollout from moving too fast with pods that came up but haven't stabilized yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values should be tuned based on the application's criticality: more conservative values (&lt;code&gt;maxUnavailable: 0&lt;/code&gt;) guarantee zero downtime during deployment, at the cost of requiring more temporary capacity in the cluster (via &lt;code&gt;maxSurge&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I have encountered downtime issues with Java applications because the new replica took too long to become available.&lt;/p&gt;

&lt;h2&gt;
  
  
  SecurityContext
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;securityContext&lt;/code&gt; defines security restrictions on how a Pod or container can run, reducing the attack surface in case the application is compromised. It can be set both at the &lt;strong&gt;Pod&lt;/strong&gt; level (applied to all containers) and at the &lt;strong&gt;container&lt;/strong&gt; level (more specific, overrides the Pod's setting).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
    &lt;span class="na"&gt;runAsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;runAsUser&lt;/code&gt; / &lt;code&gt;runAsGroup&lt;/code&gt;&lt;/strong&gt; (Pod level): forces processes to run with a specific UID/GID, instead of root, reduces potential damage if an attacker manages to execute code inside the container;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allowPrivilegeEscalation: false&lt;/code&gt;&lt;/strong&gt; (container level): prevents a process inside the container from gaining more privileges than it already has (for example, through binaries with the &lt;code&gt;setuid&lt;/code&gt; bit).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other common options worth considering, depending on the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;readOnlyRootFilesystem: true&lt;/code&gt;: makes the container's root filesystem read-only, forcing any writes to go to explicitly mounted volumes;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;capabilities.drop: ["ALL"]&lt;/code&gt;: removes all Linux capabilities by default, adding back only the ones strictly necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requests / Limits
&lt;/h2&gt;

&lt;p&gt;Without defining &lt;code&gt;requests&lt;/code&gt; and &lt;code&gt;limits&lt;/code&gt;, a container could, in theory, consume all resources available on the node it's running on, hurting other applications on the same cluster (or even bringing down the node itself).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/strong&gt;: the amount of resources Kubernetes &lt;strong&gt;reserves&lt;/strong&gt; for the container when deciding which node to schedule it on. The scheduler only places the pod on a node that has that amount available;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;limits&lt;/code&gt;&lt;/strong&gt;: the maximum ceiling the container can consume. Exceeding the &lt;strong&gt;memory&lt;/strong&gt; limit results in the container being &lt;strong&gt;killed&lt;/strong&gt; (&lt;code&gt;OOMKilled&lt;/code&gt;); exceeding the &lt;strong&gt;CPU&lt;/strong&gt; limit results in &lt;em&gt;throttling&lt;/em&gt; (the container is slowed down, but not killed).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;100m&lt;/code&gt; of CPU means 100 millicores, i.e., 0.1 of a core. Setting realistic requests (based on the application's observed usage) matters, requests that are too high waste cluster capacity; requests that are too low can lead to more pods running simultaneously than a node can actually support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Real-world application Deployment example
&lt;/h2&gt;

&lt;p&gt;Bringing together everything covered in this part: a dedicated namespace, secrets, private registry authentication, a tuned rolling update, a restrictive securityContext, and defined requests/limits, plus the Service and HorizontalPodAutoscaler already covered in previous parts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minReadySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
        &lt;span class="na"&gt;runAsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.yourcompany.com/organization/api:v9346&lt;/span&gt;
        &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-secret&lt;/span&gt;
        &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000m"&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-hpa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;targetCPUUtilizationPercentage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;75&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three objects work together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Deployment&lt;/strong&gt; runs the application with 2 replicas, authenticating with the private registry via &lt;code&gt;regcred&lt;/code&gt; and injecting sensitive configuration via &lt;code&gt;aplicacao-secret&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Service&lt;/strong&gt; exposes those replicas in a stable way on port &lt;code&gt;8080&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;HorizontalPodAutoscaler&lt;/strong&gt; monitors those replicas' CPU usage and automatically adjusts between 2 and 5, based on demand.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;These features: namespaces, secrets, secure registry authentication, a tuned rollout strategy, security restrictions, and resource limits, are typically what separates a standard manifest from one ready to run a application in production. It's worth reviewing each of these points whenever you're about to promote an application from staging to production.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k8s</category>
      <category>production</category>
      <category>devops</category>
    </item>
    <item>
      <title>Montando um Cluster Kubernetes On-Premise - Parte 7: Recursos Essenciais para Produção</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Wed, 19 Aug 2026 14:13:17 +0000</pubDate>
      <link>https://dev.to/celsonery/montando-um-cluster-kubernetes-on-premise-parte-7-recursos-essenciais-para-producao-5fpp</link>
      <guid>https://dev.to/celsonery/montando-um-cluster-kubernetes-on-premise-parte-7-recursos-essenciais-para-producao-5fpp</guid>
      <description>&lt;p&gt;🇺🇸 &lt;a href="https://dev.to/celsonery/building-an-on-premise-kubernetes-cluster-part-7-essential-production-features-446i"&gt;English version here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Montando um Cluster Kubernetes On-Premise - Parte 7: Recursos Essenciais para Produção
&lt;/h1&gt;

&lt;p&gt;Nas partes anteriores desta série, aprendemos a estrutura básica dos recursos do kubernetes e manifestos YAML. Mas existe uma distância entre "um Deployment que funciona" e "um Deployment para produção". Neste artigo, vou abordar recursos que considero indispensáveis nesse segundo cenário: &lt;strong&gt;Namespaces&lt;/strong&gt;, &lt;strong&gt;Secrets&lt;/strong&gt;, autenticação com registries privados (&lt;strong&gt;regcred&lt;/strong&gt;), &lt;strong&gt;RollingUpdate&lt;/strong&gt;, &lt;strong&gt;SecurityContext&lt;/strong&gt; e &lt;strong&gt;Requests/Limits&lt;/strong&gt;. No final, juntamos tudo em um exemplo real e completo de Deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespace
&lt;/h2&gt;

&lt;p&gt;Um &lt;strong&gt;Namespace&lt;/strong&gt; é uma forma de dividir logicamente um único cluster físico em múltiplos "clusters virtuais", útil para separar ambientes (produção, homologação, desenvolvimento) ou aplicações diferentes, evitando que cresçam misturadas em um espaço só.&lt;/p&gt;

&lt;p&gt;Criando um namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create namespace aplicacao-prod

ou 

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create ns aplicacao-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou via manifesto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listando os namespaces existentes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$kubectl&lt;/span&gt; get namespaces

ou

&lt;span class="nv"&gt;$kubectl&lt;/span&gt; get ns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir daí, praticamente todo objeto criado (Deployments, Services, Secrets) pode, e geralmente deve-se declarar em qual namespace ele vive, através do campo &lt;code&gt;metadata.namespace&lt;/code&gt; ou a flag &lt;code&gt;-n&lt;/code&gt; se for via linha de comando. Isso traz benefícios importantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolamento de nomes&lt;/strong&gt;: dois Deployments chamados &lt;code&gt;api&lt;/code&gt; podem coexistir tranquilamente, desde que estejam em namespaces diferentes;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controle de acesso (RBAC)&lt;/strong&gt;: é possível restringir o que um usuário ou uma aplicação pode fazer, escopado a um namespace específico;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organização&lt;/strong&gt;: comandos como &lt;code&gt;kubectl get pods -n aplicacao-prod&lt;/code&gt; deixam claro o que pertence a qual ambiente ou aplicação.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Se você não especificar um namespace, o Kubernetes usa o namespace &lt;code&gt;default&lt;/code&gt;, o que funciona para testes rápidos, mas não é recomendado para ambientes reais, onde múltiplas aplicações compartilham o cluster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Secrets
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secrets&lt;/strong&gt; armazenam dados sensíveis: senhas, tokens, chaves de API, de forma um pouco mais protegida que um ConfigMap comum (o conteúdo fica codificado em base64, e o acesso pode ser restrito via RBAC).&lt;/p&gt;

&lt;p&gt;Criando um Secret via linha de comando, a partir de valores literais:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic aplicacao-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;aplicacao-prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;minhasenha &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou via manifesto YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-secret&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Opaque&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bWluaGFzZW5oYQ==&lt;/span&gt;
  &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YWJjMTIz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Os valores no campo &lt;code&gt;data&lt;/code&gt; precisam estar em &lt;strong&gt;base64&lt;/strong&gt; (&lt;code&gt;echo -n 'minhasenha' | base64&lt;/code&gt;). Isso não é criptografia, é apenas uma codificação, então trate o arquivo YAML do Secret com o mesmo cuidado que trataria um arquivo de senhas em texto puro. Nunca versione (Git) um Secret com valores reais sem alguma camada adicional de proteção, como Sealed Secrets ou um cofre de segredos (Vault).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Consumindo o Secret na aplicação
&lt;/h3&gt;

&lt;p&gt;A forma mais comum é injetar todo o conteúdo do Secret como variáveis de ambiente, usando &lt;code&gt;envFrom&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minhaempresa/api:1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma, cada chave do Secret (&lt;code&gt;DB_PASSWORD&lt;/code&gt;, &lt;code&gt;API_KEY&lt;/code&gt;) vira automaticamente uma variável de ambiente dentro do container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listando as secrets de um namespace
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; get secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse comando lista todas as secrets existentes naquele namespace, mostrando nome, tipo (Opaque, kubernetes.io/dockerconfigjson, etc.) e idade, mas não mostra o conteúdo delas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detalhando uma secret específica
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; describe secret &amp;lt;nome_da_secret&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;describe&lt;/code&gt; mostra informações mais completas sobre uma secret específica, incluindo quais chaves existem dentro dela (&lt;strong&gt;DB_PASSWORD&lt;/strong&gt;, &lt;strong&gt;API_KEY&lt;/strong&gt;, etc.) e o tamanho de cada valor em bytes. Por design de segurança, porém, o describe não decodifica nem exibe o valor real de nenhuma chave, apenas confirma que ela existe e qual o tamanho do conteúdo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vistualizando o conteúdo de uma secret
&lt;/h3&gt;

&lt;p&gt;Para efetivamente ver o valor de uma chave específica, é preciso extrair o campo via &lt;code&gt;jsonpath&lt;/code&gt; e decodificar o base64 manualmente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; get secrets &amp;lt;nome_da_secret&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.DB_PASSWORD}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Use esse comando com cautela, principalmente em terminais compartilhados ou gravados (como sessões de screen/tmux logadas, ou históricos de shell salvos em texto puro). O valor decodificado aparece em texto puro diretamente na saída do terminal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Regcred - Credenciais para Registry Privado
&lt;/h2&gt;

&lt;p&gt;Quando as imagens de uma aplicação estão armazenadas em um registro privado, seja um registro próprio, seja um plano pago do Docker Hub ou de outro provedor, Kubernetes precisa de credenciais para conseguir baixar (&lt;code&gt;pull&lt;/code&gt;) essas imagens ao criar os pods. É para isso que existe o &lt;code&gt;imagePullSecret&lt;/code&gt;, comumente criado com o nome &lt;code&gt;regcred&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;O jeito mais seguro é usar um &lt;strong&gt;Deploy Token&lt;/strong&gt; do GitLab (em vez da sua senha pessoal), ele pode ser restrito a permissão somente leitura (&lt;code&gt;read_registry&lt;/code&gt;) e escopado a um projeto ou grupo específico.&lt;/p&gt;

&lt;p&gt;Criando o secret com o Deploy Token:&lt;/p&gt;

&lt;p&gt;Existem duas formas de criar esse secret: via linha de comando (mais rápida) ou via arquivo YAML (mais indicada quando você precisa versionar ou automatizar essa criação).&lt;/p&gt;

&lt;h4&gt;
  
  
  Opção 1: criando via linha de comando
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret docker-registry regcred &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; aplicacao-prod &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;registry.suaempresa.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;deploy-token-username&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;deploy-token-password&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker-email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;seu-email@suaempresa.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Onde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n namespace&lt;/code&gt;: namespace onde o secret será criado (o secret fica restrito a esse namespace);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--docker-server&lt;/code&gt;: endereço do registro privado;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--docker-username&lt;/code&gt; / &lt;code&gt;--docker-password&lt;/code&gt;: credenciais de acesso;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--docker-email&lt;/code&gt;: e-mail associado à conta (obrigatório pelo comando, ainda que não seja sempre usado na prática).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Opção 2: criando via arquivo YAML
&lt;/h4&gt;

&lt;p&gt;Se você prefere (ou precisa) versionar essa configuração, é possível montar o secret manualmente como um arquivo YAML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Crie um arquivo &lt;code&gt;config.json&lt;/code&gt;&lt;/strong&gt; com as credenciais do registro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"auths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"registry.suaempresa.com"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;deploy-token-username&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;deploy-token-password&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"seu-email@suaempresa.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Converta o arquivo para base64&lt;/strong&gt;, já que é assim que o Kubernetes espera o conteúdo do secret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;config.json | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Crie o arquivo &lt;code&gt;regcred.yaml&lt;/code&gt;&lt;/strong&gt;, colando o resultado do comando acima no campo &lt;code&gt;.dockerconfigjson&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;namespace&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubernetes.io/dockerconfigjson&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;.dockerconfigjson&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ewoJImF1dGhzIjogewoJCSJyZWdpc3RyeS5zdWFlbXByZXNhLmNvbSI6IHsKICAgICAgInVzZXJuYW1lIjogIjxkZXBsb3ktdG9rZW4tdXNlcm5hbWU+IiwKICAgICAgInBhc3N3b3JkIjogIjxkZXBsb3ktdG9rZW4tcGFzc3dvcmQ+IiwKICAgICAgImVtYWlsIjogInNldS1lbWFpbEBzdWFlbXByZXNhLmNvbSIKICAgIH0KCX0KfQo=&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nunca versione (Git) um arquivo &lt;code&gt;regcred.yaml&lt;/code&gt; com credenciais reais&lt;/strong&gt; - mesmo estando em base64, isso não é criptografia, apenas uma codificação: qualquer pessoa com acesso ao arquivo consegue decodificar e recuperar a senha original. Trate esse valor como um segredo sensível de verdade, usando ferramentas como Sealed Secrets, Vault ou variáveis de ambiente do seu pipeline de CI/CD.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;4. Aplique o secret no cluster:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; regcred.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usando o regcred em um Deployment
&lt;/h2&gt;

&lt;p&gt;Referencie o secret no Deployment através de &lt;code&gt;imagePullSecrets&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.gitlab.com/organizacao/aplicacao:v1.0.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O campo &lt;code&gt;imagePullSecrets&lt;/code&gt; aponta para o secret &lt;code&gt;regcred&lt;/code&gt; criado anteriormente, e ele &lt;strong&gt;precisa estar no mesmo namespace&lt;/strong&gt; do Pod ou Deployment que vai usá-lo.&lt;/p&gt;

&lt;h2&gt;
  
  
  RollingUpdate
&lt;/h2&gt;

&lt;p&gt;Por padrão, um Deployment já usa a estratégia &lt;code&gt;RollingUpdate&lt;/code&gt; ao atualizar a versão de uma aplicação, substituindo os pods antigos pelos novos de forma gradual, sem downtime completo. Mas os parâmetros exatos desse processo podem (e devem) ser ajustados:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minReadySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;maxSurge&lt;/code&gt;&lt;/strong&gt;: quantos pods &lt;strong&gt;a mais&lt;/strong&gt; do que o número de réplicas desejado podem ser criados temporariamente durante a atualização (aqui, 1 pod extra);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;maxUnavailable&lt;/code&gt;&lt;/strong&gt;: quantos pods podem ficar &lt;strong&gt;indisponíveis&lt;/strong&gt; simultaneamente durante a atualização (aqui, no máximo 1);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;minReadySeconds&lt;/code&gt;&lt;/strong&gt;: tempo mínimo (em segundos) que um novo pod precisa ficar "pronto" (passando nos health checks) antes de ser considerado disponível, isso evita que o rollout avance rápido demais com pods que subiram mas ainda não estabilizaram.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esses valores devem ser calibrados de acordo com a criticidade da aplicação: valores mais conservadores (&lt;code&gt;maxUnavailable: 0&lt;/code&gt;) garantem zero indisponibilidade durante o deploy, ao custo de exigir mais capacidade temporária no cluster (via &lt;code&gt;maxSurge&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Já presenciei problemas com downtime em aplicações java, pelo fato da nova réplica demorar a ficar disponível.&lt;/p&gt;

&lt;h2&gt;
  
  
  SecurityContext
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;securityContext&lt;/code&gt; define restrições de segurança sobre como um Pod ou container pode rodar, reduzindo a superfície de ataque caso a aplicação seja comprometida. Ele pode ser definido tanto no nível do &lt;strong&gt;Pod&lt;/strong&gt; (aplicado a todos os containers) quanto no nível do &lt;strong&gt;container&lt;/strong&gt; (mais específico, sobrepõe o do Pod).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
    &lt;span class="na"&gt;runAsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;runAsUser&lt;/code&gt; / &lt;code&gt;runAsGroup&lt;/code&gt;&lt;/strong&gt; (nível Pod): força os processos a rodarem com um UID/GID específico, em vez de root, reduz o dano potencial caso um invasor consiga executar código dentro do container;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;allowPrivilegeEscalation: false&lt;/code&gt;&lt;/strong&gt; (nível container): impede que um processo dentro do container obtenha mais privilégios do que os que já possui (por exemplo, através de binários com bit &lt;code&gt;setuid&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outras opções comuns que vale considerar, dependendo da aplicação:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;readOnlyRootFilesystem: true&lt;/code&gt;: torna o sistema de arquivos raiz do container somente leitura, forçando qualquer escrita a ir para volumes explicitamente montados;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;capabilities.drop: ["ALL"]&lt;/code&gt;: remove todas as capabilities do Linux por padrão, adicionando de volta apenas as estritamente necessárias.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requests / Limits
&lt;/h2&gt;

&lt;p&gt;Sem definir &lt;code&gt;requests&lt;/code&gt; e &lt;code&gt;limits&lt;/code&gt;, um container pode, teoricamente, consumir todos os recursos disponíveis no nó onde está rodando, prejudicando outras aplicações no mesmo cluster (ou até derrubando o próprio nó).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;
  &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
    &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000m"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;requests&lt;/code&gt;&lt;/strong&gt;: a quantidade de recursos que o Kubernetes &lt;strong&gt;reserva&lt;/strong&gt; para o container ao decidir em qual nó agendá-lo. O scheduler só coloca o pod em um nó que tenha essa quantidade disponível;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;limits&lt;/code&gt;&lt;/strong&gt;: o teto máximo que o container pode consumir. Ultrapassar o limite de &lt;strong&gt;memória&lt;/strong&gt; resulta no container sendo &lt;strong&gt;finalizado&lt;/strong&gt; (&lt;code&gt;OOMKilled&lt;/code&gt;); ultrapassar o limite de &lt;strong&gt;CPU&lt;/strong&gt; resulta em &lt;em&gt;throttling&lt;/em&gt; (o container é desacelerado, mas não finalizado).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;100m&lt;/code&gt; de CPU significa 100 milicores, ou seja, 0.1 de um núcleo. Definir requests realistas (baseados no consumo observado da aplicação) é importante, requests muito altos desperdiçam capacidade do cluster, requests muito baixos podem levar a mais pods do que o nó realmente suporta rodando simultaneamente.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Exemplo de Deployment de uma aplicação real
&lt;/h2&gt;

&lt;p&gt;Juntando tudo o que vimos nesta parte: namespace dedicado, secrets, autenticação com registry privado, rolling update calibrado, securityContext restritivo e requests/limits definidos, mais o Service e o HorizontalPodAutoscaler já vistos em partes anteriores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;minReadySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
    &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
        &lt;span class="na"&gt;runAsGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.suaempresa.com.br/organizacao/api:v1234&lt;/span&gt;
        &lt;span class="na"&gt;envFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-secret&lt;/span&gt;
        &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;
          &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
            &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000m"&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;regcred&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
    &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-hpa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao-prod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aplicacao&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;targetCPUUtilizationPercentage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;75&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os três objetos trabalham juntos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;Deployment&lt;/strong&gt; roda a aplicação com 2 réplicas, autenticando no registry privado via &lt;code&gt;regcred&lt;/code&gt; e injetando configurações sensíveis via &lt;code&gt;aplicacao-secret&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;Service&lt;/strong&gt; expõe essas réplicas de forma estável na porta &lt;code&gt;8080&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;HorizontalPodAutoscaler&lt;/strong&gt; monitora o uso de CPU dessas réplicas e ajusta automaticamente entre 2 e 5, conforme a demanda.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considerações finais
&lt;/h2&gt;

&lt;p&gt;Esses recursos: namespaces, secrets, autenticação segura com registries, estratégia de rollout calibrada, restrições de segurança e limites de recursos, são o que normalmente separa um manifesto comum de um manifesto para rodar uma aplicação crítica em produção. Vale revisar cada um desses pontos sempre que for promover uma aplicação de homologação para produção.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k8s</category>
      <category>production</category>
      <category>devops</category>
    </item>
    <item>
      <title>Docker - Part 6: Automating with Docker Compose</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Tue, 18 Aug 2026 23:16:51 +0000</pubDate>
      <link>https://dev.to/celsonery/part-6-orchestrating-with-docker-compose-4c5o</link>
      <guid>https://dev.to/celsonery/part-6-orchestrating-with-docker-compose-4c5o</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/parte-6-orquestrando-com-docker-compose-3545"&gt;Artigo em português aqui&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Docker - Part 6: Orchestrating with Docker Compose
&lt;/h1&gt;

&lt;p&gt;Throughout this series, we've covered containers, volumes, networks, and image management, always using individual commands like &lt;code&gt;docker run&lt;/code&gt;, &lt;code&gt;docker network create&lt;/code&gt;, &lt;code&gt;docker volume create&lt;/code&gt;, etc. That works, but it becomes tedious (and error-prone) once an application starts depending on multiple services. That's where &lt;strong&gt;Docker Compose&lt;/strong&gt; comes in: it lets you describe all of this configuration in a single declarative file, making the process cleaner, easier to repeat, and easier to version in a Git repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating your docker-compose.yaml
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A minimal docker-compose.yaml
&lt;/h3&gt;

&lt;p&gt;The simplest possible structure, running a single service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpd&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is already equivalent to running &lt;code&gt;docker run -p 80:80 httpd&lt;/code&gt;, but in a declarative, reapplyable, and easily versioned way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a volume
&lt;/h3&gt;

&lt;p&gt;To persist that service's data (as we saw in Part 3 of this series), just add a &lt;code&gt;volumes&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpd&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web-data:/usr/local/apache2/htdocs&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the volume needs to be declared in two places: referenced inside the service (&lt;code&gt;volumes:&lt;/code&gt; under &lt;code&gt;web&lt;/code&gt;) and defined in the root-level &lt;code&gt;volumes:&lt;/code&gt; section at the end of the file, that's where Compose actually creates the named volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a network
&lt;/h3&gt;

&lt;p&gt;Likewise, you can declare custom networks (covered in Part 4):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;httpd&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web-data:/usr/local/apache2/htdocs&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app-network&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In practice, when you don't explicitly declare a network, Compose already creates a default network for the project automatically, allowing services within the same &lt;code&gt;docker-compose.yaml&lt;/code&gt; to see each other by name. Declaring networks manually is worth it when you need more than one isolated network, or want to connect services across different Compose files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bringing up the containers
&lt;/h2&gt;

&lt;p&gt;To create and start all the services defined in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like with &lt;code&gt;docker run&lt;/code&gt;, the terminal stays "stuck," showing the logs of all services. To run it in the background:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tearing down the containers
&lt;/h2&gt;

&lt;p&gt;To stop and remove the containers and networks, while (by default) preserving the volumes created by Compose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;By default, &lt;code&gt;docker compose down&lt;/code&gt; &lt;strong&gt;does not remove volumes&lt;/strong&gt;, this prevents accidental data loss. If you want to remove volumes too, use &lt;code&gt;docker compose down -v&lt;/code&gt; (with caution).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bringing multiple containers together: App + Database + Redis
&lt;/h2&gt;

&lt;p&gt;Compose's real power shows up when an application depends on multiple services working together. A common example: an Nginx proxy in front, an application, a MySQL database, and a Redis cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx.conf:/etc/nginx/conf.d/default.conf:ro&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app-network&lt;/span&gt;

  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp:1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="na"&gt;DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appuser&lt;/span&gt;
      &lt;span class="na"&gt;DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apppassword&lt;/span&gt;
      &lt;span class="na"&gt;REDIS_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app-network&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rootpassword&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appdb&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appuser&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apppassword&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db-data:/var/lib/mysql&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app-network&lt;/span&gt;

  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:alpine&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app-network&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few important points from this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;depends_on&lt;/code&gt;&lt;/strong&gt;: defines the startup order of the containers (&lt;code&gt;app&lt;/code&gt; only starts after &lt;code&gt;db&lt;/code&gt; and &lt;code&gt;redis&lt;/code&gt;). Note this only guarantees the &lt;em&gt;starting&lt;/em&gt; order of the container, not that the internal service (like MySQL) is already ready to accept connections, for that, the application usually needs to implement some retry logic on the database connection;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment variables&lt;/strong&gt; (&lt;code&gt;environment&lt;/code&gt;): used to configure the application and MySQL without needing to modify images or hardcode values;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;db-data&lt;/code&gt;&lt;/strong&gt;: a named volume ensuring MySQL's data survives container restarts and recreations;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;app-network&lt;/code&gt;&lt;/strong&gt;: all services share the same network, letting them communicate with each other by service name (&lt;code&gt;db&lt;/code&gt;, &lt;code&gt;redis&lt;/code&gt;) instead of fixed IPs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bringing everything up at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a single command, Compose creates the network, the volumes, and brings up all four containers already connected and ready to talk to each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Series wrap-up
&lt;/h2&gt;

&lt;p&gt;Throughout this series, we covered the complete day-to-day Docker lifecycle: installation, essential CLI commands, data persistence with volumes, container-to-container communication via networks, image management and publishing, and finally, orchestrating multiple services with Docker Compose. With this foundation, you now have everything you need to run containerized applications professionally, whether in a local development environment or on a production server.&lt;/p&gt;

&lt;p&gt;For anyone looking to go beyond a single host, the natural next step is &lt;strong&gt;Kubernetes&lt;/strong&gt;, which solves the same orchestration problems, but at scale, distributing containers across multiple servers.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>compose</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Docker - Part 5: Managing Images</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Tue, 18 Aug 2026 23:15:22 +0000</pubDate>
      <link>https://dev.to/celsonery/part-5-managing-images-5137</link>
      <guid>https://dev.to/celsonery/part-5-managing-images-5137</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/parte-5-gerenciando-imagens-ble"&gt;Artigo em português aqui&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Docker - Part 5: Managing Images
&lt;/h1&gt;

&lt;p&gt;In Part 4 of this series, we covered how containers communicate through networks. Now let's tackle the lifecycle of Docker &lt;strong&gt;images&lt;/strong&gt;: how to build your own, list the ones already available locally, version them correctly, and publish them to a registry, whether Docker Hub or a private registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building an image
&lt;/h2&gt;

&lt;p&gt;To build an image from a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; &amp;lt;image_name&amp;gt;:&amp;lt;version&amp;gt; &lt;span class="nt"&gt;-f&lt;/span&gt; dockerfile &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-t &amp;lt;image_name&amp;gt;:&amp;lt;version&amp;gt;&lt;/code&gt;: sets the name and tag (version) of the resulting image; if the version is released, a 'latest' version will be created;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-f dockerfile&lt;/code&gt;: specifies which Dockerfile to use (useful when you have multiple Dockerfiles in the same directory, or a non-default filename); if there is only one Dockerfile at the project root, this argument can be omitted;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt;: sets the &lt;strong&gt;build context&lt;/strong&gt;, the directory whose contents become available to instructions like &lt;code&gt;COPY&lt;/code&gt; and &lt;code&gt;ADD&lt;/code&gt; inside the Dockerfile.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Dockerfile example:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:alpine&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk upgrade &lt;span class="nt"&gt;--no-cache&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./index.html ./&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; [ "nginx", "-g", "daemon off;" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FROM&lt;/code&gt;: Specifies the base image to be used.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RUN&lt;/code&gt;: Commands to execute in order to build the application before building the image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WORKDIR&lt;/code&gt;: Specifies the internal location within the image where operations are currently taking place.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COPY&lt;/code&gt;: Command to copy files from the local application into the Docker image.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXPOSE&lt;/code&gt;: Specifies the port the container will listen on.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CMD&lt;/code&gt;: Command for the final execution of the application. (In this case, I am running Nginx).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Listing images
&lt;/h2&gt;

&lt;p&gt;To see all images already downloaded or built locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Versioning images (tag)
&lt;/h2&gt;

&lt;p&gt;Before publishing an image to a registry, you generally need to "tag" it with the full destination address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker tag &amp;lt;local_image_name&amp;gt;:&amp;lt;version&amp;gt; &amp;lt;remote_registry&amp;gt;/&amp;lt;remote_image_name&amp;gt;:&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, tagging a local &lt;code&gt;myapp:1.0.0&lt;/code&gt; image for Docker Hub, under the user &lt;code&gt;celsonery&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker tag myapp:1.0.0 celsonery/myapp:1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or for a private registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker tag myapp:1.0.0 registry.yourcompany.com/myapp:1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;It's considered good practice to use &lt;strong&gt;semantic versioning&lt;/strong&gt; in your tags (&lt;code&gt;1.0.0&lt;/code&gt;, &lt;code&gt;1.0.1&lt;/code&gt;, &lt;code&gt;1.1.0&lt;/code&gt;) instead of relying solely on the &lt;code&gt;latest&lt;/code&gt; tag, since &lt;code&gt;latest&lt;/code&gt; doesn't indicate exactly which version is running in production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Removing images
&lt;/h2&gt;

&lt;p&gt;To remove a specific image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image &lt;span class="nb"&gt;rm&lt;/span&gt; &amp;lt;image_name&amp;gt;:&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cleaning up unused images
&lt;/h2&gt;

&lt;p&gt;Intermediate images and images no longer referenced by any container tend to pile up over time, taking up disk space. To clean up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker image prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Publishing an image (push)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;To publish an image, you must first authenticate with a registry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Docker Hub (default)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Private registry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the destination isn't Docker Hub, you need to provide the server address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker login registry.yourcompany.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Push to Docker Hub
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker push &amp;lt;image_name&amp;gt;:&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Push to a private registry
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker push &amp;lt;registry&amp;gt;/&amp;lt;image_name&amp;gt;:&amp;lt;version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Remember: the image needs to have been &lt;strong&gt;tagged&lt;/strong&gt; (previous step) with the full destination registry address before the &lt;code&gt;push&lt;/code&gt;, otherwise, Docker will try to send it to Docker Hub by default.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;With the complete image lifecycle covered, build, tag, push, you can now distribute your own applications as versioned images. In &lt;strong&gt;Part 6&lt;/strong&gt;, the last of this series, we'll bring everything we've covered together (volumes, networks, multiple containers) using &lt;strong&gt;Docker Compose&lt;/strong&gt;, making it much simpler and more organized to manage applications with multiple services.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continued in Part 6.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Docker - Part 4: Working with Networks</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Tue, 18 Aug 2026 23:13:48 +0000</pubDate>
      <link>https://dev.to/celsonery/part-4-working-with-networks-32po</link>
      <guid>https://dev.to/celsonery/part-4-working-with-networks-32po</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/docker-para-desenvolvedores-parte-4-trabalhando-com-redes-2c70"&gt;Artigo em português aqui&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Docker - Part 4: Working with Networks
&lt;/h1&gt;

&lt;p&gt;In Part 3 of this series, we covered persisting data with volumes. Now let's tackle another fundamental pillar of multi-container applications: &lt;strong&gt;networking&lt;/strong&gt;. When an application depends on several services (for example, an API that needs to talk to a database), those containers need to be able to communicate with each other, and that's what Docker networks make possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Listing networks
&lt;/h2&gt;

&lt;p&gt;Docker already creates a few default networks on installation (&lt;code&gt;bridge&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;none&lt;/code&gt;). To list all existing networks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a network
&lt;/h2&gt;

&lt;p&gt;To create a custom network, isolated from the others:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network create &amp;lt;network_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Containers connected to the same custom network can communicate with each other using the &lt;strong&gt;container name&lt;/strong&gt; as the hostname, no need to discover or hardcode IP addresses manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspecting a network
&lt;/h2&gt;

&lt;p&gt;To see details about a network, such as the IP range, driver used, and which containers are connected to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network inspect &amp;lt;network_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running a container already connected to a network
&lt;/h2&gt;

&lt;p&gt;To create a container and connect it to a specific network right at creation time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--net&lt;/span&gt; &amp;lt;network_name&amp;gt; httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting a running container to a network
&lt;/h2&gt;

&lt;p&gt;If the container is already running and you want to add it to an additional network (a container can belong to multiple networks at once):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network connect &lt;span class="nt"&gt;--ip&lt;/span&gt; 192.168.100.10 &amp;lt;network_name&amp;gt; httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--ip&lt;/code&gt; flag lets you pin a specific IP for the container within that network, useful when other applications need a predictable address to connect to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disconnecting a container from a network
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network disconnect &amp;lt;network_name&amp;gt; httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Removing a network
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network &lt;span class="nb"&gt;rm&lt;/span&gt; &amp;lt;network_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A network can only be removed if no container is currently connected to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cleaning up unused networks
&lt;/h2&gt;

&lt;p&gt;Just like with volumes, it's common to accumulate orphaned networks over time. To remove all networks not currently used by any container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker network prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Running isolated containers without a custom network works fine for quick tests, but as soon as an application needs multiple services talking to each other (app + database + cache, for example), custom networks stop being optional. They provide isolation (containers from different projects can't see each other by default) and simple name-based communication, without relying on manually managed fixed IPs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;With volumes for persistence and networks for communication between containers, we now have the two fundamental pieces needed to run multi-service applications. In &lt;strong&gt;Part 5&lt;/strong&gt; of this series, we'll cover &lt;strong&gt;image management&lt;/strong&gt;: how to build, version (tag), and publish your own images to a registry.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continued in Part 5.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>networking</category>
      <category>devops</category>
    </item>
    <item>
      <title>Docker - Part 3: Persisting Data with Volumes</title>
      <dc:creator>Celso Nery</dc:creator>
      <pubDate>Tue, 18 Aug 2026 23:12:00 +0000</pubDate>
      <link>https://dev.to/celsonery/part-3-persisting-data-with-volumes-1ig3</link>
      <guid>https://dev.to/celsonery/part-3-persisting-data-with-volumes-1ig3</guid>
      <description>&lt;p&gt;🇧🇷 &lt;a href="https://dev.to/celsonery/parte-3-persistindo-dados-com-volumes-1mk4"&gt;Artigo em português aqui&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Docker - Part 3: Persisting Data with Volumes
&lt;/h1&gt;

&lt;p&gt;In Part 2 of this series, we covered the essential commands for operating containers day to day. But there's an important detail: by default, data written inside a container is &lt;strong&gt;ephemeral&lt;/strong&gt;, if the container is removed, that data disappears with it. For stateful applications (databases, user uploads, configuration files), that's a problem. That's what &lt;strong&gt;volumes&lt;/strong&gt; exist to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bind mount vs. Volume
&lt;/h2&gt;

&lt;p&gt;There are two main ways to persist data outside a container's lifecycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bind mount&lt;/strong&gt;: mounts a specific folder from the &lt;strong&gt;host&lt;/strong&gt; (the machine running Docker) inside the container. You have full control over where the data lives on the host, but you become more dependent on that specific machine's folder structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume&lt;/strong&gt;: managed by Docker itself, stored in an internal area (&lt;code&gt;/var/lib/docker/volumes/&lt;/code&gt; on Linux). This is the recommended approach for most cases, since it's more portable across environments and easier to back up, inspect, and clean up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article focuses on &lt;strong&gt;volumes&lt;/strong&gt;, the recommended approach for professional use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a volume
&lt;/h2&gt;

&lt;p&gt;To create a named volume that will store an application's data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create vol_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Listing volumes
&lt;/h2&gt;

&lt;p&gt;To see all volumes that already exist on the system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inspecting a volume
&lt;/h2&gt;

&lt;p&gt;To see details about a specific volume, such as the actual path where the data is stored on the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume inspect vol_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running a container with a volume &lt;code&gt;-v&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using a bind mount
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; local_folder:remote_folder httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;local_folder&lt;/code&gt; is an absolute path on the host (for example, &lt;code&gt;/home/celso/data&lt;/code&gt;), and &lt;code&gt;remote_folder&lt;/code&gt; is the path inside the container where that data should appear (for example, &lt;code&gt;/var/www/htdocs/&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Using a created volume
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; volume_name:remote_folder httpd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;volume_name&lt;/code&gt; is the name of the volume created earlier with &lt;code&gt;docker volume create&lt;/code&gt;, Docker handles where that data is physically stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing a volume
&lt;/h2&gt;

&lt;p&gt;If any container is still using the volume, you'll need to remove the container first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm&lt;/span&gt; &amp;lt;container_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, to remove the volume:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume &lt;span class="nb"&gt;rm &lt;/span&gt;vol_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cleaning up unused volumes
&lt;/h2&gt;

&lt;p&gt;Over time, it's common to accumulate orphaned volumes (created by containers that have since been removed). To clean up all volumes not currently used by any container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This command permanently removes the data of any volume not referenced by an active container, confirm before running this on an environment with important data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Using NFS volumes
&lt;/h2&gt;

&lt;p&gt;In environments with multiple Docker hosts (or when you want to share data across different servers), you can create a volume pointing to an &lt;strong&gt;NFS&lt;/strong&gt; share instead of local storage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create &lt;span class="nt"&gt;--opt&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nfs &lt;span class="nt"&gt;--opt&lt;/span&gt; &lt;span class="nv"&gt;o&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;addr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10.0.0.35,rw,nfsvers&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="nt"&gt;--opt&lt;/span&gt; &lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;:/home/nfsshare nfs-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type=nfs&lt;/code&gt;: sets the volume driver to NFS;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;o=addr=10.0.0.35,rw,nfsvers=4&lt;/code&gt;: NFS server address and mount options (read/write, protocol version);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;device=:/home/nfsshare&lt;/code&gt;: path exported by the NFS server;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nfs-volume&lt;/code&gt;: name given to the volume in Docker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially useful in scenarios where multiple containers (possibly on different hosts) need access to the same shared data set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;With volumes handling data persistence, the next challenge is communication &lt;strong&gt;between&lt;/strong&gt; containers, especially when an application depends on multiple services (for example, an API that needs to talk to a database). In &lt;strong&gt;Part 4&lt;/strong&gt; of this series, we'll look at how to create and manage &lt;strong&gt;networks&lt;/strong&gt; in Docker.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Continued in Part 4.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>linux</category>
      <category>volumes</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
