<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Anarcher&#39;s Trashcan</title>
    <link>https://blog.anarcher.dev/</link>
    <description>Recent content on Anarcher&#39;s Trashcan</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>ted@daangn.com (Anarcher)</managingEditor>
    <webMaster>ted@daangn.com (Anarcher)</webMaster>
    <copyright>Anarcher CC BY-SA</copyright>
    <atom:link href="https://blog.anarcher.dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>When Kubernetes Nodes Exceed 1000</title>
      <link>https://blog.anarcher.dev/post/2025/08-15-prom-endpoints/</link>
      <pubDate>Fri, 15 Aug 2025 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2025/08-15-prom-endpoints/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When Kubernetes nodes exceed 1000, node exporters deployed as DaemonSets on each node also increase.&lt;/li&gt;
&lt;li&gt;When Prometheus Operator performs Service discovery with Service monitor, it references the service&amp;rsquo;s endpoints by default.&lt;/li&gt;
&lt;li&gt;Kubernetes Endpoints objects have a default limit of 1000 IPs.&lt;/li&gt;
&lt;li&gt;Only 1000 Prometheus scrape targets are maintained.&lt;/li&gt;
&lt;li&gt;Prometheus should use endpointslices instead of Kubernetes endpoints for Service discovery.&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;As Kubernetes clusters grow and the number of nodes exceeds 1000, various challenges arise. One particularly important issue from a monitoring perspective is Prometheus Service Discovery.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>TL;DR</strong></p>
<ol>
<li>When Kubernetes nodes exceed 1000, node exporters deployed as DaemonSets on each node also increase.</li>
<li>When Prometheus Operator performs Service discovery with Service monitor, it references the service&rsquo;s endpoints by default.</li>
<li>Kubernetes Endpoints objects have a default limit of 1000 IPs.</li>
<li>Only 1000 Prometheus scrape targets are maintained.</li>
<li>Prometheus should use endpointslices instead of Kubernetes endpoints for Service discovery.</li>
</ol></blockquote>
<p>As Kubernetes clusters grow and the number of nodes exceeds 1000, various challenges arise. One particularly important issue from a monitoring perspective is Prometheus Service Discovery.</p>
<p>For node-exporter, cadvisor, kubelet metrics, etc. deployed as DaemonSets on each node, the number of endpoints increases with the node count. For example:</p>
<ul>
<li>node-exporter: 1000 nodes = 1000 targets</li>
<li>kubelet metrics: 1000 nodes = 1000 targets</li>
<li>cadvisor: 1000 nodes = 1000 targets</li>
</ul>
<p>The problem lies in the limitations of Kubernetes&rsquo; default Endpoints object. A single Endpoints object can only store up to 1000 IP addresses. When nodes exceed 1000, nodes from 1001 onwards are not included in the Endpoints, resulting in Prometheus being unable to scrape them.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># kubectl get endpoints node-exporter -n monitoring -o yaml</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: Endpoints
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: node-exporter
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">namespace</span>: monitoring
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">subsets</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">addresses</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">ip</span>: <span style="color:#fab387">10.0.1.1</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">ip</span>: <span style="color:#fab387">10.0.1.2</span>
</span></span><span style="display:flex;"><span>      <span style="color:#6c7086;font-style:italic"># ... up to 1000 only</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">ip</span>: <span style="color:#fab387">10.0.4.232</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">port</span>: <span style="color:#fab387">9100</span>
</span></span><span style="display:flex;"><span>        <span style="color:#cba6f7">protocol</span>: TCP</span></span></code></pre></div>
<p>In this situation, if metrics from some nodes are not collected, monitoring blind spots occur and alarms may not work properly.</p>
<h1 id="endpoints-and-endpointslices">Endpoints and EndpointSlices</h1>
<p>Kubernetes Endpoints objects store IP addresses of Pods connected to Services. However, there are several limitations:</p>
<ol>
<li><strong>Size limitation</strong>: A single Endpoints object can store a maximum of 1000 IPs</li>
<li><strong>Performance issues</strong>: Large Endpoints objects burden etcd and the API server</li>
<li><strong>Update inefficiency</strong>: The entire Endpoints object is updated even when a single Pod changes</li>
</ol>
<p>EndpointSlices, introduced from Kubernetes 1.16, were designed to solve these problems:</p>
<ol>
<li><strong>Distributed storage</strong>: Stored as multiple small objects (100 endpoints per slice by default)</li>
<li><strong>Efficient updates</strong>: Only modified slices are updated</li>
<li><strong>Scalability</strong>: Can scale without node count limitations</li>
</ol>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># kubectl get endpointslices -n monitoring -l kubernetes.io/service-name=node-exporter</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: discovery.k8s.io/v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: EndpointSlice
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: node-exporter-abc123
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">namespace</span>: monitoring
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">kubernetes.io/service-name</span>: node-exporter
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">addressType</span>: IPv4
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">endpoints</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">addresses</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#fab387">10.0.1.1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">conditions</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#cba6f7">ready</span>: <span style="color:#fab387">true</span>
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">addresses</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#fab387">10.0.1.2</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">conditions</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#cba6f7">ready</span>: <span style="color:#fab387">true</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># ... up to 100</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">ports</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">port</span>: <span style="color:#fab387">9100</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">protocol</span>: TCP
</span></span><span style="display:flex;"><span><span style="color:#fab387">---</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: discovery.k8s.io/v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: EndpointSlice
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: node-exporter-def456
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">namespace</span>: monitoring
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">kubernetes.io/service-name</span>: node-exporter
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># ... next 100</span></span></span></code></pre></div>
<h3 id="comparison-table">Comparison Table</h3>
<table>
  <thead>
      <tr>
          <th>Feature</th>
          <th>Endpoints</th>
          <th>EndpointSlices</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Max IP count</td>
          <td>1000</td>
          <td>Unlimited (distributed across slices)</td>
      </tr>
      <tr>
          <td>Object size</td>
          <td>Large and single</td>
          <td>Small and multiple</td>
      </tr>
      <tr>
          <td>Update efficiency</td>
          <td>Low (full update)</td>
          <td>High (partial update)</td>
      </tr>
      <tr>
          <td>API server load</td>
          <td>High</td>
          <td>Low</td>
      </tr>
      <tr>
          <td>Introduced in</td>
          <td>v1.0</td>
          <td>v1.16 (GA: v1.21)</td>
      </tr>
  </tbody>
</table>
<h3 id="endpoints-api-deprecation">Endpoints API Deprecation</h3>
<p>Starting from Kubernetes 1.33, the Endpoints API is officially deprecated, and the API server returns warnings to users who read or write Endpoints resources without using EndpointSlices. For more details, see the <a href="https://kubernetes.io/blog/2025/04/24/endpoints-deprecation/">official Kubernetes blog</a>.</p>
<h2 id="prometheus-operators-servicediscoveryrole">Prometheus Operator&rsquo;s serviceDiscoveryRole</h2>
<p>When using Prometheus Operator, scrape targets are defined through the ServiceMonitor CRD. ServiceMonitor discovers targets by referencing Kubernetes Service Endpoints by default.</p>
<p><a href="https://kubespec.dev/prometheus-operator/monitoring.coreos.com/v1/Prometheus">Prometheus Operator v0.81.0 Spec: Prometheus</a></p>
<p>Starting from Prometheus Operator v0.50.0, the <code>serviceDiscoveryRole</code> field was introduced to allow selecting the Service Discovery method:</p>
<p><img src="/post/2025/08-15-prom-endpoints/1.png" alt=""></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: monitoring.coreos.com/v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: Prometheus
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: kube-prometheus
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">namespace</span>: monitoring
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">serviceDiscoveryRole: EndpointSlice # default</span>: Endpoints
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">serviceMonitorSelector</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">matchLabels</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#cba6f7">team</span>: platform</span></span></code></pre></div>
<p>Possible values:</p>
<ul>
<li><code>Endpoints</code>: Use traditional Endpoints objects (default)</li>
<li><code>EndpointSlice</code>: Use EndpointSlices</li>
</ul>
<h3 id="considerations-when-changing-settings">Considerations When Changing Settings</h3>
<ol>
<li><strong>Check Kubernetes version</strong>: EndpointSlices are available in k8s 1.16+, GA in 1.21+</li>
<li><strong>Update RBAC permissions</strong>: Need to add permissions for Prometheus to read EndpointSlices</li>
</ol>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: rbac.authorization.k8s.io/v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: ClusterRole
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: prometheus
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">rules</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">apiGroups</span>: [<span style="color:#a6e3a1">&#34;discovery.k8s.io&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">resources</span>:
</span></span><span style="display:flex;"><span>      - endpointslices
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">verbs</span>: [<span style="color:#a6e3a1">&#34;get&#34;</span>, <span style="color:#a6e3a1">&#34;list&#34;</span>, <span style="color:#a6e3a1">&#34;watch&#34;</span>]</span></span></code></pre></div>
<ol start="3">
<li><strong>Gradual migration</strong>: Validate in test environment first before applying to production</li>
</ol>
<h2 id="prometheus-operator-and-kubelet-endpoints">Prometheus Operator and Kubelet Endpoints</h2>
<p>Kubelet metrics work differently from the typical Service/Endpoints pattern. Kubelet is a system component running on each node that must be accessed directly without a Service object.</p>
<p>Prometheus Operator automatically creates and manages Endpoints objects for collecting kubelet metrics by default:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: Endpoints
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: kubelet
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">namespace</span>: kube-system
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">app.kubernetes.io/managed-by</span>: prometheus-operator <span style="color:#6c7086;font-style:italic"># Managed by Operator</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">app.kubernetes.io/name</span>: kubelet
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">k8s-app</span>: kubelet
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">subsets</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">addresses</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">ip</span>: <span style="color:#fab387">10.0.1.1</span> <span style="color:#6c7086;font-style:italic"># node1</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">ip</span>: <span style="color:#fab387">10.0.1.2</span> <span style="color:#6c7086;font-style:italic"># node2</span>
</span></span><span style="display:flex;"><span>    <span style="color:#6c7086;font-style:italic"># ... can store up to 1000 only</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#cba6f7">name</span>: https-metrics
</span></span><span style="display:flex;"><span>        <span style="color:#cba6f7">port</span>: <span style="color:#fab387">10250</span></span></span></code></pre></div>
<p>The <code>app.kubernetes.io/managed-by: prometheus-operator</code> label indicates that these Endpoints are automatically managed by Prometheus Operator.</p>
<h3 id="issues">Issues</h3>
<p>When Prometheus&rsquo;s serviceDiscoveryRole is changed to EndpointSlice, kubelet also uses EndpointSlice. However, Kubernetes EndpointSlice mirroring has a 1000 limit:</p>
<ul>
<li>EndpointSlice mirroring controller mirrors (by default) a maximum of 1000 endpoints (<a href="https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/#endpointslice-mirroring">reference</a>)</li>
<li>With more than 1000 nodes, EndpointSlice cannot scrape all kubelets</li>
</ul>
<h3 id="solutions">Solutions</h3>
<h4 id="1-safe-migration-strategy-recommended">1. Safe Migration Strategy (Recommended)</h4>
<p>This is the safe migration method suggested in Prometheus Operator GitHub issue <a href="https://github.com/prometheus-operator/prometheus-operator/issues/7678">#7678</a>:</p>
<p><strong>Step 1: Configure to manage both objects</strong></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># Prometheus Operator Deployment</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: apps/v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: Deployment
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: prometheus-operator
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">namespace</span>: monitoring
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">template</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">spec</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#cba6f7">containers</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#cba6f7">name</span>: prometheus-operator
</span></span><span style="display:flex;"><span>          <span style="color:#cba6f7">args</span>:
</span></span><span style="display:flex;"><span>            - --kubelet-endpoints=true <span style="color:#6c7086;font-style:italic"># Continue managing Endpoints</span>
</span></span><span style="display:flex;"><span>            - --kubelet-endpointslice=true <span style="color:#6c7086;font-style:italic"># Also manage EndpointSlice</span></span></span></code></pre></div>
<p><strong>Step 2: Verify EndpointSlice object creation</strong></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># Verify that EndpointSlice was created successfully</span>
</span></span><span style="display:flex;"><span>kubectl get endpointslices -n kube-system -l kubernetes.io/service-name<span style="color:#89dceb;font-weight:bold">=</span>kubelet
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># Check created EndpointSlice</span>
</span></span><span style="display:flex;"><span>kubectl get endpointslice kubelet-8jkql -n kube-system -o yaml</span></span></code></pre></div>
<p>The created EndpointSlice includes the following labels:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">app.kubernetes.io/managed-by</span>: prometheus-operator
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">endpointslice.kubernetes.io/managed-by</span>: prometheus-operator <span style="color:#6c7086;font-style:italic"># Directly managed by Operator</span>
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">kubernetes.io/service-name</span>: kubelet</span></span></code></pre></div>
<p><strong>Step 3: Configure Prometheus to use EndpointSlice</strong></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: monitoring.coreos.com/v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: Prometheus
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">name</span>: kube-prometheus
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">spec</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">serviceDiscoveryRole</span>: EndpointSlice <span style="color:#6c7086;font-style:italic"># Use EndpointSlice</span></span></span></code></pre></div>
<p><strong>Step 4: Disable Endpoints after confirming normal operation</strong></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"># Disable Endpoints management when everything works normally</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">args</span>:
</span></span><span style="display:flex;"><span>  - --kubelet-endpoints=false <span style="color:#6c7086;font-style:italic"># Stop creating Endpoints</span>
</span></span><span style="display:flex;"><span>  - --kubelet-endpointslice=true <span style="color:#6c7086;font-style:italic"># Manage only EndpointSlice</span></span></span></code></pre></div>
<h4 id="2-preventing-endpointslice-mirroring">2. Preventing EndpointSlice Mirroring</h4>
<p>Endpoints managed by Prometheus Operator have special labels added:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">apiVersion</span>: v1
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: Endpoints
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">app.kubernetes.io/managed-by</span>: prometheus-operator
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">endpointslice.kubernetes.io/skip-mirror</span>: <span style="color:#a6e3a1">&#34;true&#34;</span> <span style="color:#6c7086;font-style:italic"># Prevent mirroring</span></span></span></code></pre></div>
<p>The <code>endpointslice.kubernetes.io/skip-mirror: &quot;true&quot;</code> label prevents Kubernetes&rsquo;s EndpointSlice mirroring controller from automatically mirroring these Endpoints to EndpointSlice. This is because Prometheus Operator directly manages the EndpointSlice.</p>
<h4 id="3-before-and-after-migration-comparison">3. Before and After Migration Comparison</h4>
<p><strong>Before migration (managed by Mirroring Controller):</strong></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: EndpointSlice
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">endpointslice.kubernetes.io/managed-by</span>: endpointslicemirroring-controller.k8s.io</span></span></code></pre></div>
<p><strong>After migration (directly managed by Prometheus Operator):</strong></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">kind</span>: EndpointSlice
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">app.kubernetes.io/managed-by</span>: prometheus-operator
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">endpointslice.kubernetes.io/managed-by</span>: prometheus-operator <span style="color:#6c7086;font-style:italic"># Directly managed by Operator</span></span></span></code></pre></div>
<h2 id="conclusion">Conclusion</h2>
<p>When Kubernetes clusters grow beyond 1000 nodes, monitoring systems must be designed to scale accordingly. By utilizing EndpointSlices, stable metric collection is possible without node count limitations. Migration can be easily accomplished through Prometheus Operator&rsquo;s <code>serviceDiscoveryRole</code> setting, and for kubelet metrics, the transition can be made using both <code>--kubelet-endpoints</code> and <code>--kubelet-endpointslice</code> flags together.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A toy tool for generating Kubernetes manifests in Rust</title>
      <link>https://blog.anarcher.dev/post/2025/05-25-kamut/</link>
      <pubDate>Sun, 25 May 2025 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2025/05-25-kamut/</guid>
      <description>&lt;p&gt;My personal criticism of Helm is the part where it generates Kubernetes resources by composing YAML with text templates. Actually, the template/values pattern of Helm charts is also used in kube-prometheus&amp;rsquo;s jsonnet, and there&amp;rsquo;s a need to abstract and manage complex configurations.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>My personal criticism of Helm is the part where it generates Kubernetes resources by composing YAML with text templates. Actually, the template/values pattern of Helm charts is also used in kube-prometheus&rsquo;s jsonnet, and there&rsquo;s a need to abstract and manage complex configurations.</p>
<p>I particularly think that Kubernetes resources are not suitable for text templating like HTML. These manifest files represent various APIs supported by Kubernetes and are essentially structured data. And I thought that the most effective tool for processing structured data is a programming language.</p>
<p>Given that Kubernetes is essentially an API, and all operations performed within a Kubernetes cluster (such as creating Pods or monitoring services) ultimately involve interaction with that API. The Kubernetes API server automatically generates and provides complete OpenAPI specifications for all resources and operations.</p>
<p>So with the help of (recently trendy) vibe coding, I wrote <a href="https://github.com/anarcher/kamut">kamut</a> in Rust.</p>
<p>The basic structure is simple. By writing <code>deploy.kamut.yaml</code> as follows, you can generate <code>deploy.yaml</code> with the <code>kamut</code> CLI.</p>
<p><code>deploy.kamut.yaml</code></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>kind: Deployment
</span></span><span style="display:flex;"><span>name: my-app
</span></span><span style="display:flex;"><span>image: nginx:latest
</span></span><span style="display:flex;"><span>replicas: 3
</span></span><span style="display:flex;"><span>env:
</span></span><span style="display:flex;"><span>  APP_ENV: production
</span></span><span style="display:flex;"><span>  DEBUG: &#34;false&#34;
</span></span><span style="display:flex;"><span>resources:
</span></span><span style="display:flex;"><span>  requests:
</span></span><span style="display:flex;"><span>    cpu: 100m
</span></span><span style="display:flex;"><span>    memory: 128Mi
</span></span><span style="display:flex;"><span>  limits:
</span></span><span style="display:flex;"><span>    cpu: 200m
</span></span><span style="display:flex;"><span>    memory: 256Mi</span></span></code></pre></div>
<p><code>deploy.yaml</code></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>apiVersion: apps/v1
</span></span><span style="display:flex;"><span>kind: Deployment
</span></span><span style="display:flex;"><span>metadata:
</span></span><span style="display:flex;"><span>  name: my-app
</span></span><span style="display:flex;"><span>spec:
</span></span><span style="display:flex;"><span>  replicas: 3
</span></span><span style="display:flex;"><span>  selector:
</span></span><span style="display:flex;"><span>    matchLabels:
</span></span><span style="display:flex;"><span>      app: my-app
</span></span><span style="display:flex;"><span>  template:
</span></span><span style="display:flex;"><span>    metadata:
</span></span><span style="display:flex;"><span>      labels:
</span></span><span style="display:flex;"><span>        app: my-app
</span></span><span style="display:flex;"><span>    spec:
</span></span><span style="display:flex;"><span>      containers:
</span></span><span style="display:flex;"><span>      - name: my-app
</span></span><span style="display:flex;"><span>        image: nginx:latest
</span></span><span style="display:flex;"><span>        env:
</span></span><span style="display:flex;"><span>        - name: APP_ENV
</span></span><span style="display:flex;"><span>          value: production
</span></span><span style="display:flex;"><span>        - name: DEBUG
</span></span><span style="display:flex;"><span>          value: &#34;false&#34;
</span></span><span style="display:flex;"><span>        resources:
</span></span><span style="display:flex;"><span>          requests:
</span></span><span style="display:flex;"><span>            cpu: 100m
</span></span><span style="display:flex;"><span>            memory: 128Mi
</span></span><span style="display:flex;"><span>          limits:
</span></span><span style="display:flex;"><span>            cpu: 200m
</span></span><span style="display:flex;"><span>            memory: 256Mi</span></span></code></pre></div>
<p>Because it uses definitions for structured data (structs generated based on OpenAPI spec), validation of structural flaws is possible during manifest generation. Actually, generation becomes impossible if there are structural issues.</p>
<p>In Rust, there are also libraries for definitions of resource types in the Kubernetes client API that are automatically generated from the Kubernetes OpenAPI specification.</p>
<ul>
<li><a href="https://github.com/metio/kube-custom-resources-rs">metio/kube-custom-resources-rs: Kubernetes Custom Resource Bindings for Rust</a></li>
<li><a href="https://github.com/Arnavion/k8s-openapi">Arnavion/k8s-openapi: Rust definitions of the resource types in the Kubernetes client API</a></li>
</ul>
<p>Since Kamut is a toy project for learning Rust, if you&rsquo;re interested in this approach and want to try it out, I&rsquo;d recommend <a href="https://yokecd.github.io/docs/">yoke</a>. ;-)</p>
]]></content:encoded>
    </item>
    <item>
      <title>GreptimeDB as Prometheus Long-term Storage</title>
      <link>https://blog.anarcher.dev/post/2025/04-13-greptimedb-intro/</link>
      <pubDate>Sun, 13 Apr 2025 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2025/04-13-greptimedb-intro/</guid>
      <description>&lt;p&gt;Is GreptimeDB suitable as a long-term storage solution for Prometheus? To find an answer to this question, I set up a simple configuration of GreptimeDB (v0.13) to investigate.&lt;/p&gt;
&lt;h2 id=&#34;what-is-greptimedb&#34;&gt;What is GreptimeDB?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://greptime.com&#34;&gt;GreptimeDB&lt;/a&gt; is an open-source cloud-native time series database that integrates metrics, logs, and events.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Is GreptimeDB suitable as a long-term storage solution for Prometheus? To find an answer to this question, I set up a simple configuration of GreptimeDB (v0.13) to investigate.</p>
<h2 id="what-is-greptimedb">What is GreptimeDB?</h2>
<p><a href="https://greptime.com">GreptimeDB</a> is an open-source cloud-native time series database that integrates metrics, logs, and events.</p>
<h1 id="greptimedb-as-prometheus-long-term-storage">GreptimeDB as Prometheus Long-term Storage</h1>
<p>Key features include:</p>
<p>Unified Data Model: It can handle metrics, logs, and events (possibly traces too?) in a single database. GreptimeDB&rsquo;s data model treats all time series as events with timestamps and context, allowing management under a single model. GreptimeDB supports SQL, enabling queries that can retrieve both metrics and logs in a single query.</p>
<p><img src="/post/2025/04-13-greptimedb-intro/unified-data-model.png" alt="image"></p>
<p>Support for Various Collection Protocols: Supports various observability data including Prometheus, InfluxDB, MySQL, OpenTSDB, etc.</p>
<p>Parquet-based Column Storage: Efficient structure for high cardinality data</p>
<p>Computing and Storage Separation Based on Cloud Object Storage: Independent scalability of each resource</p>
<p>Various Indexing Strategies: In Prometheus, all labels are indexed. GreptimeDB allows you to set indexing for specific labels (tags) only. (Both Scanning+Pruning and Indexing can be used)</p>
<h1 id="architecture">Architecture</h1>
<p><img src="/post/2025/04-13-greptimedb-intro/architecture.png" alt="image"></p>
<ul>
<li><code>Metasrv</code>: <code>Metasrv</code> manages database and table information. This includes how data is distributed within the cluster and how collection and query requests are routed. (Requires etcd by default, but also supports pgsql and mysql).</li>
<li><code>Frontend</code>: Supports various collection/query protocols and forwards requests to the <code>Datanode</code> according to the direction of <code>Metasrv</code> for collection and queries.</li>
<li><code>Datanode</code>: Manages table regions in the cluster. It receives read and write requests forwarded from the <code>Frontend</code>, processes the data, and returns results.</li>
</ul>
<p>Cortex or Mimir manages only the ingester information in etcd or consul as a hashring (though they use gossip protocol these days). Compared to this, GreptimeDB&rsquo;s metasrv manages not only the status of each component but also the table partitioning information, making it contain more metadata and requiring greater stability.</p>
<h1 id="installation">Installation</h1>
<p>GreptimeDB supports <a href="https://github.com/GreptimeTeam/greptimedb-operator">GreptimeTeam/greptimedb-operator: Run GreptimeDB on Kubernetes.</a> to support operation on Kubernetes.</p>
<p>It also supports <a href="https://github.com/GreptimeTeam/helm-charts">GreptimeTeam/helm-charts: Helm charts for deploy GreptimeDB.</a>, making configuration easy.</p>
<h2 id="prometheus-and-greptimedbs-data-model">Prometheus and GreptimeDB&rsquo;s Data Model</h2>
<p>GreptimeDB&rsquo;s data model is composed of Tables with Tags, Fields, and Timestamps. It can be viewed as a multi-value data model similar to InfluxDB&rsquo;s data model, and it <strong>automatically</strong> groups multiple Prometheus metrics into (physical) tables.
<img src="/post/2025/04-13-greptimedb-intro/datamodel-1.png" alt="image"></p>
<p>While Prometheus labels are all indexed, GreptimeDB&rsquo;s data model explicitly distinguishes between tags and fields.
Low-cardinality labels can be configured as tags that are indexed (not all tags need to be indexed).
High-cardinality data can be configured as fields (while Prometheus is fixed with labels and value, schema configuration in GreptimeDB can be more flexible).
And by grouping into tables, storage and query efficiency can be achieved by eliminating duplicate fields.</p>
<p><img src="/post/2025/04-13-greptimedb-intro/datamodel-2.png" alt="image"></p>
<p><img src="/post/2025/04-13-greptimedb-intro/datamodel-3.png" alt="image"></p>
<p>GreptimeDB&rsquo;s frontend supports Prometheus remote write and Prometheus HTTP API (which can be used as a Grafana data source).</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">remote_write</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">url</span>: http://localhost:4000/v1/prometheus/write?db=public
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">remote_read</span>:
</span></span><span style="display:flex;"><span>  - <span style="color:#cba6f7">url</span>: http://localhost:4000/v1/prometheus/read?db=public</span></span></code></pre></div>
<p>While Cortex or Thanos separates the ingest component and query component, GreptimeDB&rsquo;s frontend handles both. Since these two workloads are different, it would be appropriate to divide the frontend into read-only and write-only configurations.</p>
<h1 id="table-region-and-datanode">Table Region and Datanode</h1>
<p>I have Prometheus configured as a collector for each Kubernetes cluster and forward it to long-term storage via Prometheus remote write (collecting all metrics in Prometheus).
In this structure, when forwarding to GreptimeDB as long-term storage, I discovered that metrics weren&rsquo;t distributed across multiple datanodes but rather routed to a single datanode.</p>
<p><img src="/post/2025/04-13-greptimedb-intro/memory-increase.png" alt="Memory increase of a single datanode"></p>
<p>From my experience with Cortex/Thanos, I thought metrics should be distributed across multiple ingesters (datanodes) (but I was wrong).
The reason metrics are collected into a single datanode is (to get to the conclusion) there is only one physical table for metrics. Therefore, only one datanode provides all logical regions of that table. So you can find multiple regions in the same datanode. <a href="https://docs.greptime.com/contributor-guide/datanode/metric-engine/#physical-table">Metric Engine | GreptimeDB Documentation | Unified Time-Series Database</a></p>
<p>If you want to distribute workload across multiple datanodes, you need to partition the table. However, it seemed there was no approach yet to evenly partition by hashing <code>job</code> labels.</p>
<p>And because metrics are collected into a single datanode, if that node restarts or is in poor condition, it will fail to read all metrics. There should be datanodes (follower peers) that can distribute reads other than the datanode (leader peer) responsible for writes, but this isn&rsquo;t available yet and is planned to be activated in the enterprise edition. <a href="https://github.com/GreptimeTeam/greptimedb/issues/5739">Tracking Issues / Follower regions · Issue #5739 · GreptimeTeam/greptimedb</a></p>
<p>&hellip;</p>
<h1 id="conclusion">Conclusion</h1>
<p>Looking at GreptimeDB so far, I learned several interesting points in the process. To list them somewhat randomly:</p>
<ul>
<li>The distinction between write and read layers is necessary.</li>
<li>The distinction between processing recent data and long-term data is necessary.</li>
<li>When Prometheus TSDB labels have very high cardinality, storing and searching the inverted index is costly. On the other hand, the scanning+pruning approach commonly used in analytical databases can effectively handle such scenarios, and a hybrid approach might be more effective.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Jsonnet: The Good, the Bad, and the Meh</title>
      <link>https://blog.anarcher.dev/post/2023/05-04-jsonnet/</link>
      <pubDate>Thu, 04 May 2023 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2023/05-04-jsonnet/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Each solution is the root of the next problem
&amp;ndash; Gerald M. Weinberg&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve been using Jsonnet for several years, and I think it would be good to summarize my experiences so far.&lt;/p&gt;
&lt;h1 id=&#34;the-good&#34;&gt;The good&lt;/h1&gt;
&lt;p&gt;The best thing about Jsonnet is that it&amp;rsquo;s a superset of JSON. As a data templating language for generating JSON, it provides many features of programming languages (variables, functions, arithmetic operations, conditionals). Since it can generate JSON, it can also generate YAML, which is why I use it with &lt;a href=&#34;https://tanka.dev&#34;&gt;tanka&lt;/a&gt; to create Kubernetes manifests.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>Each solution is the root of the next problem
&ndash; Gerald M. Weinberg</p></blockquote>
<p>I&rsquo;ve been using Jsonnet for several years, and I think it would be good to summarize my experiences so far.</p>
<h1 id="the-good">The good</h1>
<p>The best thing about Jsonnet is that it&rsquo;s a superset of JSON. As a data templating language for generating JSON, it provides many features of programming languages (variables, functions, arithmetic operations, conditionals). Since it can generate JSON, it can also generate YAML, which is why I use it with <a href="https://tanka.dev">tanka</a> to create Kubernetes manifests.</p>
<p>In my opinion, the biggest drawback of Helm is its simple Go/template-based templating. I believe the following template work exemplifies the problems that arise in templating languages that fundamentally don&rsquo;t understand their output:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#cba6f7">metadata</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">labels</span>:
</span></span><span style="display:flex;"><span>    {{- include &#34;ingress-nginx.labels&#34; . | nindent 4 }}
</span></span><span style="display:flex;"><span>    {{- with .Values.controller.labels }}
</span></span><span style="display:flex;"><span>    {{- toYaml . | nindent 4 }}
</span></span><span style="display:flex;"><span>    {{- end }}
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">annotations</span>: {{ toYaml .Values.controller.annotations | nindent 4 }}
</span></span><span style="display:flex;"><span><span style="color:#fab387">...</span></span></span></code></pre></div>
<p>If written in Jsonnet, it would look like:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#f38ba8">metadata:</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">local</span> <span style="color:#f38ba8">labels</span> <span style="color:#f38ba8">=</span> <span style="color:#f38ba8">import</span> <span style="color:#cba6f7">&#34;ingress-nginx-labels.jsonnet&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">labels:</span> <span style="color:#f38ba8">labels</span> <span style="color:#f38ba8">+</span> <span style="color:#f38ba8">$.values.controller.labels,</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">annotations:</span> <span style="color:#f38ba8">$.values.controller.annotations,</span>
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
<blockquote>
<p>Above, $ refers to the top-level object at the time of evaluation. In other words, it points to the outermost object when the Jsonnet file is evaluated. In contrast, <code>self</code> refers to the object currently being defined.</p></blockquote>
<p>Helm treats templates as strings without understanding the target. Jsonnet templates JSON by adding various language features.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">a:</span> <span style="color:#f38ba8">1,</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">b:</span> <span style="color:#f38ba8">self.a</span> <span style="color:#f38ba8">+</span> <span style="color:#f38ba8">1,</span>  <span style="color:#6c7086;font-style:italic">// self.a references 1, result is 2
</span></span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"></span>  <span style="color:#f38ba8">nested:</span> <span style="color:#f38ba8">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">x:</span> <span style="color:#f38ba8">10,</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">y:</span> <span style="color:#f38ba8">self.x</span> <span style="color:#f38ba8">+</span> <span style="color:#f38ba8">5,</span>  <span style="color:#6c7086;font-style:italic">// self.x references 10, result is 15
</span></span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"></span>    <span style="color:#f38ba8">z:</span> <span style="color:#f38ba8">$.a</span> <span style="color:#f38ba8">+</span> <span style="color:#f38ba8">5</span>      <span style="color:#6c7086;font-style:italic">// $.a references the top-level object&#39;s a(1), result is 6
</span></span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"></span>  }
</span></span><span style="display:flex;"><span><span style="color:#f38ba8">}</span></span></span></code></pre></div>
<p>Helm&rsquo;s &ldquo;oil and water strategy&rdquo; is similar to inserting Smalltalk syntax into C like in Objective-C, and is widely used when templating HTML in web servers.</p>
<p>However, this strategy feels like wiring your brain in two layers. Having a template language that understands what it&rsquo;s templating is (in my personal opinion) a good approach, not a bad one - especially when the target is defined in YAML or JSON, like with Kubernetes.</p>
<h1 id="the-bad">The bad</h1>
<p>Jsonnet&rsquo;s <code>Merging</code> feature allows you to modify an object from multiple files.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#f38ba8">local</span> <span style="color:#f38ba8">baseConfig</span> <span style="color:#f38ba8">=</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">name:</span> <span style="color:#cba6f7">&#34;app&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">resources:</span> <span style="color:#f38ba8">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">memory:</span> <span style="color:#cba6f7">&#34;1Gi&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">cpu:</span> <span style="color:#cba6f7">&#34;100m&#34;</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span><span style="color:#f38ba8">};</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f38ba8">local</span> <span style="color:#f38ba8">overrides</span> <span style="color:#f38ba8">=</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">resources:</span> <span style="color:#f38ba8">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">memory:</span> <span style="color:#cba6f7">&#34;2Gi&#34;</span>
</span></span><span style="display:flex;"><span>  }<span style="color:#f38ba8">,</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">replicas:</span> <span style="color:#fab387">3</span>
</span></span><span style="display:flex;"><span><span style="color:#f38ba8">};</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Result will have merged fields
</span></span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic"></span><span style="color:#f38ba8">baseConfig</span> <span style="color:#f38ba8">+</span> <span style="color:#f38ba8">overrides</span></span></span></code></pre></div>
<p>The result is:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">&#34;name&#34;</span>: <span style="color:#a6e3a1">&#34;app&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">&#34;resources&#34;</span>: {
</span></span><span style="display:flex;"><span>    <span style="color:#cba6f7">&#34;memory&#34;</span>: <span style="color:#a6e3a1">&#34;2Gi&#34;</span>
</span></span><span style="display:flex;"><span>  },
</span></span><span style="display:flex;"><span>  <span style="color:#cba6f7">&#34;replicas&#34;</span>: <span style="color:#fab387">3</span>
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
<p>The interesting point here is that the contents of <code>resources</code> have been replaced with the contents from <code>overrides</code>. If you want to merge the contents of <code>resources</code> from <code>baseConfig</code> with those from <code>overrides</code>, you would do:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#f38ba8">local</span> <span style="color:#f38ba8">overrides</span> <span style="color:#f38ba8">=</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">resources+:</span> <span style="color:#f38ba8">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f38ba8">memory:</span> <span style="color:#cba6f7">&#34;2Gi&#34;</span>
</span></span><span style="display:flex;"><span>  }<span style="color:#f38ba8">,</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f38ba8">replicas:</span> <span style="color:#fab387">3</span>
</span></span><span style="display:flex;"><span><span style="color:#f38ba8">};</span></span></span></code></pre></div>
<p>By using <code>resources+:</code>, the contents of resources are merged rather than replaced. This feature effectively makes all objects open.</p>
<p>Helm is a combination of templates + values. While this makes it difficult to use values in ways that deviate from the intent of the templates, it also has the advantage of formalizing usage to reduce structural complexity.
<a href="https://github.com/prometheus-operator/kube-prometheus/tree/main/jsonnet/kube-prometheus">kube-prometheus/jsonnet/kube-prometheus</a> adopts this structural characteristic (advantage) of <code>helm</code> with its <code>components</code> and <code>values</code> structure.</p>
<p>However, having all objects always open is both an advantage and a disadvantage. The kube-prometheus structure is just a kind of pattern that cannot be enforced. Things can always become complex.</p>
<h1 id="the-meh">The meh</h1>
<p>In my personal experience, debugging Jsonnet is always difficult. You can output intermediate objects with <code>std.trace()</code>, but that&rsquo;s not enough. Although this is a problem derived from Jsonnet&rsquo;s power, I think there should be more linguistic constraints to prevent users from misusing Jsonnet. This thought leads me to consider <a href="https://cuelang.org/">CUE</a>. For large and complex manifests, CUE could provide more stability. But that might mean losing the advantages that come with Jsonnet&rsquo;s power. (In some ways, the advantage is also the disadvantage.)</p>
<h1 id="conclusion">Conclusion</h1>
<p>While Jsonnet&rsquo;s charm is good, its advantages seem to fade in complex structures. Since Kubernetes manifests are essentially requests to the Kubernetes API, I sometimes wonder if the answer might be to generate them using regular programming languages, like <a href="https://github.com/bwplotka/mimic">bwplotka/mimic: mimic: Define your Deployments, Infrastructure and Configuration as a Go Code 🚀</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Some notes about cortex architecture</title>
      <link>https://blog.anarcher.dev/post/2022/05-10-cortex/</link>
      <pubDate>Tue, 10 May 2022 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2022/05-10-cortex/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://cortexmetrics.io/&#34;&gt;Cortex&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cortex, started by Tom Wilkie and Julius Volz (Prometheus&amp;rsquo; co-founder) in 2016, has several interesting architectural features. As one of Prometheus&amp;rsquo; long-term storage solutions, Cortex has been referenced by many time-series based storage architectures (tracing, log) since then (especially in the Grafana stack).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://cortexmetrics.io/">Cortex</a></p>
<p>Cortex, started by Tom Wilkie and Julius Volz (Prometheus&rsquo; co-founder) in 2016, has several interesting architectural features. As one of Prometheus&rsquo; long-term storage solutions, Cortex has been referenced by many time-series based storage architectures (tracing, log) since then (especially in the Grafana stack).</p>
<p><img src="/post/2022/05-10-cortex/cortex-architecture.png" alt="image"></p>
<h1 id="prometheus">Prometheus</h1>
<p>Prometheus can be considered a kind of monolithic architecture.
<img src="/post/2022/05-10-cortex/prometheus-architecture.png" alt="image"></p>
<p>Because everything is together, technical problems (that arise in microservices) do not occur, but each component cannot be scaled individually according to its specific purpose. In some ways, Cortex can be seen as a microservice version of Prometheus.</p>
<h1 id="ingester--distributor">Ingester &amp; Distributor</h1>
<p><img src="/post/2022/05-10-cortex/ingester-distributor.png" alt="image"></p>
<p>In Cortex, the ingester is the most important component. It&rsquo;s the component that collects time series through Prometheus remote write, and since Prometheus TSDB creates blocks every 2 hours, it needs to respond to querier&rsquo;s query requests for metrics from the last 2 hours.
Since it holds the TSDB&rsquo;s Head Block in memory, it&rsquo;s fast for recent metric requests. Due to the nature of time series usage, recent data usage is an important pattern (e.g., for alerts).</p>
<p>Data replication is important for reliability in any distributed system design. The Distributor also copies the same data to multiple Ingesters according to the RF (Replication Factor). It might seem like a waste of resources, but if a specific ingester fails, another ingester with replicated data can respond. From a query performance perspective, queries can be distributed based on duplicated data.</p>
<p>Ingesters don&rsquo;t need to know much about each other. This advantage creates another disadvantage: duplicated data is uploaded to S3. Later, the compactor cleans up this duplicated data (similar to LSM Tree).</p>
<p>What happens if an ingester restarts before uploading a block (before 2 hours)? The ingester must upload the data it has so far to S3 during shutdown.</p>
<h1 id="store-gateway--compactor">Store gateway &amp; Compactor</h1>
<p>Looking at the TSDB structure, a database called a block is created hourly, and data is stored as index and chunks within the block.
The ingester stores these TSDB blocks in an object store (S3), and the store gateway finds and delivers the necessary TSDB in response to querier requests. Since the store gateway needs to retrieve large amounts of data from the slow object store, it uses caches for the index and chunks, and query performance depends heavily on the cache hit ratio.</p>
<p>The compactor takes blocks that start at 2 hours and gradually creates larger blocks with increased time spans. Since there are duplicate indexes across different time periods, compaction also has a (positive) impact on query performance.</p>
<h1 id="some-notes-about-cortex-architecture">Some notes about Cortex architecture</h1>
<p>In my personal opinion, Cortex architecture seems like a kind of distributed and coordination-(half)free architecture.
If you look at RDB sharding solutions, they have a lot of meta information needed for coordination between each component, but Cortex only maintains simple status and connection information for ingesters in metastores like Consul.
They don&rsquo;t hold much information about each other and allow duplicated data and fan out requests redundantly, but because they don&rsquo;t know much about each other, they can act simply.</p>
]]></content:encoded>
    </item>
    <item>
      <title>kroller : a tiny (restart) tool to help for kubernetes cluster upgrade</title>
      <link>https://blog.anarcher.dev/post/2021/02-12-kroller/</link>
      <pubDate>Fri, 12 Feb 2021 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2021/02-12-kroller/</guid>
      <description>&lt;p&gt;Kubernetes upgrades (especially EKS) are categorized into two types based on the Kubernetes architecture:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control plane upgrade (+ etcd)&lt;/li&gt;
&lt;li&gt;Node upgrade&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Particularly when using cloud-managed Kubernetes like EKS, since AWS manages the control plane, you&amp;rsquo;ll mostly handle node upgrades directly (if you&amp;rsquo;re not using managed nodegroups).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Kubernetes upgrades (especially EKS) are categorized into two types based on the Kubernetes architecture:</p>
<ul>
<li>Control plane upgrade (+ etcd)</li>
<li>Node upgrade</li>
</ul>
<p>Particularly when using cloud-managed Kubernetes like EKS, since AWS manages the control plane, you&rsquo;ll mostly handle node upgrades directly (if you&rsquo;re not using managed nodegroups).</p>
<p>When you upgrade the control plane, you&rsquo;ll have nodes with different versions of kubelet as shown in the diagram below:</p>
<p><img src="/post/2021/02-12-kroller/kubernetes-version-nodes.png" alt="image"></p>
<p>For clusters that are not large-scale, you would typically create a new node group of the same size as the current one and relocate pods from the previous node group to the newly created node group (temporarily maintaining twice the number of nodes).</p>
<p>In this case, you need an efficient way to relocate all applications. But what exactly is relocation? Despite its name, is it any different from a regular deployment?</p>
<p>Approaching exceptional situations as normal ones helps prevent many problems. In reality, although we call it relocation, it&rsquo;s not much different from a regular deployment except that the purpose is relocation.</p>
<p>However, since it&rsquo;s inconvenient to relocate (redeploy, restart) hundreds of applications at once, I wrote a simple CLI for a kind of simple automation.</p>
<p><a href="https://github.com/anarcher/kroller">anarcher/kroller</a></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kroller -h
</span></span><span style="display:flex;"><span>USAGE
</span></span><span style="display:flex;"><span>  kroller &lt;subcommand&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SUBCOMMANDS
</span></span><span style="display:flex;"><span>  restart  restart all rollout resources
</span></span><span style="display:flex;"><span>  drain    drain node
</span></span><span style="display:flex;"><span>  show     show details of nodes or resources
</span></span><span style="display:flex;"><span>  version  show version of kroller
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FLAGS
</span></span><span style="display:flex;"><span>  -kubeconfig ...  kubeconfig file
</span></span><span style="display:flex;"><span>  -v <span style="color:#89dceb">false</span>         log verbose output</span></span></code></pre></div>
<p>Looking at the list of subcommands, first there&rsquo;s a command called <code>restart</code>.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ kroller restart -h
</span></span><span style="display:flex;"><span>USAGE
</span></span><span style="display:flex;"><span>  restart all rollout resources <span style="color:#89dceb;font-weight:bold">(</span>deployment,statefulset<span style="color:#89dceb;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FLAGS
</span></span><span style="display:flex;"><span>  -config ...         config file <span style="color:#89dceb;font-weight:bold">(</span>optional<span style="color:#89dceb;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span>  -kubeconfig ...     kubeconfig file
</span></span><span style="display:flex;"><span>  -target ...         only use the specified objects <span style="color:#89dceb;font-weight:bold">(</span>Format: &lt;namespace&gt;/&lt;type&gt;/&lt;name&gt;<span style="color:#89dceb;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span>  -v <span style="color:#89dceb">false</span>            log verbose output</span></span></code></pre></div>
<p>The most interesting flag is <code>-target</code>.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>  -target ...         only use the specified objects (Format: &lt;namespace&gt;/&lt;type&gt;/&lt;name&gt;)</span></span></code></pre></div>
<p>As a cluster grows over time and includes many Kubernetes objects, you might need to operate on only a subset of them (e.g., apply to only certain applications).</p>
<p>The <code>-target</code> flag provides the ability to limit which objects to restart. <code>(Format: &lt;namespace&gt;/&lt;type&gt;/&lt;name&gt;)</code> Especially since it supports <a href="https://github.com/google/re2/wiki/Syntax">RE2</a>, you can use all kinds of wildcards and other advanced matching features to select Kubernetes objects.</p>
<p><img src="/post/2021/02-12-kroller/target-flag-example.png" alt="image"></p>
<blockquote>
<p>The format and structure of this flag is borrowed from <a href="https://tanka.dev/output-filtering/#_top">Output filtering | Grafana Tanka</a>.</p></blockquote>
<p>Next is the <code>-config</code> flag. It&rsquo;s not common to restart all applications at once; instead, you&rsquo;d typically perform a phased operation. For example, you might distinguish between service applications and addons (e.g., ingress, etc.) for staged redeployment.
In such cases, rather than writing <code>-target</code> each time, you write a config file and run it.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span># flux-system.cfg
</span></span><span style="display:flex;"><span>target flux-system/deployment/.*
</span></span><span style="display:flex;"><span>v</span></span></code></pre></div>
<p><img src="/post/2021/02-12-kroller/config-file-example.png" alt="image"></p>
<p>The config file is simply writing the flags for <code>kroller restart</code> to a file. So not just <code>-target</code> but other flags can be written to the config file as well.</p>
<p>There are also features like <code>kroller show nodes</code> to check nodes and pods.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Prometheus 101 (slide) and Graphite</title>
      <link>https://blog.anarcher.dev/post/2019/09-25-prom-101/</link>
      <pubDate>Wed, 25 Sep 2019 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2019/09-25-prom-101/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://slide.anarcher.dev/2019/prometheus-101/#1&#34;&gt;Prometheus 101&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.anarcher.dev/post/2019/09-25-prom-101/prom-101-slide.png&#34; alt=&#34;slide: Prometheus 101&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.anarcher.dev/post/2019/09-25-prom-101/image1.png&#34; alt=&#34;slide: query&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.anarcher.dev/post/2019/09-25-prom-101/image2.png&#34; alt=&#34;slide: range vector&#34;&gt;&lt;/p&gt;
&lt;p&gt;I created a simple presentation about Prometheus. I uploaded it using &lt;a href=&#34;https://github.com/sporto/hugo-remark&#34;&gt;sporto/hugo-remark: A theme for using remark.js with hugo&lt;/a&gt;, and I found that creating it in markdown rather than PowerPoint allowed me to focus more on the content. (But that doesn&amp;rsquo;t necessarily mean the content is better.)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://slide.anarcher.dev/2019/prometheus-101/#1">Prometheus 101</a></p>
<p><img src="/post/2019/09-25-prom-101/prom-101-slide.png" alt="slide: Prometheus 101"></p>
<p><img src="/post/2019/09-25-prom-101/image1.png" alt="slide: query"></p>
<p><img src="/post/2019/09-25-prom-101/image2.png" alt="slide: range vector"></p>
<p>I created a simple presentation about Prometheus. I uploaded it using <a href="https://github.com/sporto/hugo-remark">sporto/hugo-remark: A theme for using remark.js with hugo</a>, and I found that creating it in markdown rather than PowerPoint allowed me to focus more on the content. (But that doesn&rsquo;t necessarily mean the content is better.)</p>
<p>| &ldquo;He who knows one, knows none&rdquo; - <a href="https://en.wikipedia.org/wiki/Max_M%C3%BCller">Max Müller</a></p>
<p>Prometheus is the monitoring system I encountered after <a href="https://graphiteapp.org/">Graphite</a>. Graphite is a metric-based monitoring system written in Python. But due to its file-based TSDB characteristics, it&rsquo;s difficult to solve <code>Series Churn</code> problems when they occur(One file per time series).
This problem got worse when cloud environments like AWS were set up, because servers became instances.</p>
<p><img src="/post/2019/09-25-prom-101/image3.png" alt="series churn"></p>
<p>While Prometheus isn&rsquo;t completely free from this problem, it has a fundamentally better structure because it handles data in blocks and chunks. (I believe I heard that Prometheus TSDB v1 had a structure similar to Graphite.)</p>
<p>Graphite performs metric aggregation during collection through carbon relay, but if some metrics that are targets for aggregation arrive late due to network instability, the aggregation results become distorted. (We often described these metric graphs as having &ldquo;missing teeth&rdquo;.)</p>
<p>In contrast, Prometheus uses a pull model, and its <code>Recording Rules</code> approach queries metrics collected in the TSDB for aggregation. This makes reliability easier to guarantee. While Graphite can discard raw metrics after aggregation, Prometheus must first store raw metrics in the TSDB to perform aggregation.</p>
<p>In my personal opinion, scraping targets has better manageability than receiving metrics from thousands of servers. (Of course, Service Discovery functionality is necessary for this.)</p>
]]></content:encoded>
    </item>
    <item>
      <title>Make REST API Documentation using swagger in Go</title>
      <link>https://blog.anarcher.dev/post/2018/01-20-rest-api-doc-go-swagger/</link>
      <pubDate>Sat, 20 Jan 2018 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2018/01-20-rest-api-doc-go-swagger/</guid>
      <description>&lt;p&gt;For golang based HTTP/REST API documentation,I choose &lt;a href=&#34;https://swagger.io/&#34;&gt;swagger&lt;/a&gt;. &lt;a href=&#34;https://goswagger.io/&#34;&gt;go-swagger&lt;/a&gt; has several features for swagger documentation. The go-swagger can generate swagger spec based code generation but I already have an REST API server. I use go-swagger with golang comment annotation for swagger spec generation.&lt;/p&gt;
&lt;p&gt;For REST API development, Design first with writing spec and then generating codes from it is a good approach. &lt;a href=&#34;https://goa.design/&#34;&gt;goa&lt;/a&gt; is a famous tool for this style.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>For golang based HTTP/REST API documentation,I choose <a href="https://swagger.io/">swagger</a>. <a href="https://goswagger.io/">go-swagger</a> has several features for swagger documentation. The go-swagger can generate swagger spec based code generation but I already have an REST API server. I use go-swagger with golang comment annotation for swagger spec generation.</p>
<p>For REST API development, Design first with writing spec and then generating codes from it is a good approach. <a href="https://goa.design/">goa</a> is a famous tool for this style.</p>
<h1 id="generate-go-swagger-spec">Generate go-swagger spec</h1>
<p>The go-swagger has a command that will let you generate a swagger spec document from codes. The command scan all files from current directory or specific file path to sub directories.</p>
<p>To generate a spec:</p>
<p><code>swagger generate spec</code> command makes swagger.json spec.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Package rest HTTP API.</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">//</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Schemes: http</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Host: localhost</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// BasePath: /</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Version: 0.0.1</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Consumes:</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// - application/json</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// Produces:</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// - application/json</span>
</span></span><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// swagger:meta</span>
</span></span><span style="display:flex;"><span><span style="color:#94e2d5">package</span> rest</span></span></code></pre></div>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>//go:generate swagger generate spec -m -i ./swagger.yml -o ./static/swagger.json</span></span></code></pre></div>
<h1 id="operations-and-struct-model-mapping">Operations and struct model mapping</h1>
<p>One of reasons why I choose swagger or api documentation generation tool is that parsing source code and using on api spec.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> swagger:operation POST <span style="color:#89dceb;font-weight:bold">/</span>v1<span style="color:#89dceb;font-weight:bold">/</span>articles Article create_article
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> Create an article resource
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> <span style="color:#89dceb;font-weight:bold">---</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> summary: Create article
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> parameters:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>  <span style="color:#89dceb;font-weight:bold">-</span> <span style="color:#89dceb;font-weight:bold">in</span>: body
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>    required: <span style="color:#89dceb">true</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>    schema:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>       <span style="color:#89dceb;font-weight:bold">$</span>ref: <span style="color:#a6e3a1">&#34;#/definitions/createArticleRequest&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> responses:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span> responses:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>  <span style="color:#a6e3a1">&#39;200&#39;</span>:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>   description: successful operation
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>   schema:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>    <span style="color:#89dceb;font-weight:bold">$</span>ref: <span style="color:#a6e3a1">&#34;#/definitions/Article&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>  <span style="color:#a6e3a1">&#39;500&#39;</span>:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>   description: failed operation (error)
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>   schema:
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>    <span style="color:#89dceb;font-weight:bold">$</span>ref: <span style="color:#a6e3a1">&#34;#/definitions/Error&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">//</span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">func</span> createAppHandler(context <span style="color:#89dceb;font-weight:bold">*</span>gin<span style="color:#89dceb;font-weight:bold">.</span>Context) {
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">...</span></span></span></code></pre></div>
<p>The <code>definitions/Article</code> and <code>definitions/Error</code> are mapping from struct with <code>swagger:model</code></p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#6c7086;font-style:italic">// swagger:model</span>
</span></span><span style="display:flex;"><span><span style="color:#f38ba8">type</span> Article <span style="color:#f38ba8">struct</span> {
</span></span><span style="display:flex;"><span>    ID         <span style="color:#f38ba8">string</span>    <span style="color:#a6e3a1">`db:&#34;id&#34; json:&#34;id&#34; yaml:&#34;id&#34;`</span>
</span></span><span style="display:flex;"><span>    Name       <span style="color:#f38ba8">string</span>    <span style="color:#a6e3a1">`db:&#34;name&#34; json:&#34;name&#34; yaml:&#34;name&#34;`</span>
</span></span><span style="display:flex;"><span>    CreateTime time.Time <span style="color:#a6e3a1">`db:&#34;create_time&#34; json:&#34;create_time&#34;`</span>
</span></span><span style="display:flex;"><span>    UpdateTime time.Time <span style="color:#a6e3a1">`db:&#34;update_time&#34; json:&#34;update_time&#34;`</span>
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
<p>It is convenient if you have complex request and response payloads.</p>
<h1 id="embedded-static-assetswaggerjson-with-go-bindata">Embedded static asset(swagger.json) with go-bindata</h1>
<p>I want to embedded the swagger-ui and <a href="https://github.com/Rebilly/ReDoc">redoc</a> frontend page to my rest api server. <a href="https://github.com/jteeuwen/go-bindata">go-bindata</a> converts any text or binary file into Go source code.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#cba6f7">go</span>:generate <span style="color:#cba6f7">go</span><span style="color:#89dceb;font-weight:bold">-</span>bindata <span style="color:#89dceb;font-weight:bold">-</span>prefix <span style="color:#a6e3a1">&#34;static/&#34;</span> <span style="color:#89dceb;font-weight:bold">-</span>o static<span style="color:#89dceb;font-weight:bold">/</span>bindata.<span style="color:#cba6f7">go</span> <span style="color:#89dceb;font-weight:bold">-</span>pkg static static<span style="color:#89dceb;font-weight:bold">/...</span></span></span></code></pre></div>
<p>That&rsquo;s it. the <code>swagger.json</code> is embedded in golang code. With gin framework, you can use it with <a href="https://github.com/olebedev/staticbin">staticbin</a>.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#94e2d5">import</span>  <span style="color:#a6e3a1">&#34;github.com/olebedev/staticbin&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">...</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>router.<span style="color:#89b4fa">Use</span>(staticbin.<span style="color:#89b4fa">Static</span>(static.Asset, staticbin.Options{
</span></span><span style="display:flex;"><span>        Dir: <span style="color:#a6e3a1">&#34;/static&#34;</span>,
</span></span><span style="display:flex;"><span>}))</span></span></code></pre></div>
<p>Embedded with swagger-ui, you can use <a href="https://github.com/utahta/swagger-doc">swagger-doc</a>&rsquo;s assets for it.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#94e2d5">import</span> (
</span></span><span style="display:flex;"><span>    swaggerDoc <span style="color:#a6e3a1">&#34;github.com/utahta/swagger-doc&#34;</span>
</span></span><span style="display:flex;"><span>    swaggerAsset <span style="color:#a6e3a1">&#34;github.com/utahta/swagger-doc/assets&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb;font-weight:bold">...</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>router.<span style="color:#89b4fa">Use</span>(staticbin.<span style="color:#89b4fa">Static</span>(swaggerAsset.Asset, staticbin.Options{
</span></span><span style="display:flex;"><span>        Dir: <span style="color:#a6e3a1">&#34;/swagger-ui&#34;</span>,
</span></span><span style="display:flex;"><span>}))
</span></span><span style="display:flex;"><span>router.<span style="color:#89b4fa">Any</span>(<span style="color:#a6e3a1">&#34;/redoc&#34;</span>, gin.<span style="color:#89b4fa">WrapH</span>(swaggerDoc.<span style="color:#89b4fa">NewRedocHandler</span>(<span style="color:#a6e3a1">&#34;/static/swagger.json&#34;</span>, <span style="color:#a6e3a1">&#34;redoc&#34;</span>)))</span></span></code></pre></div>
<p>I&rsquo;m not sure this approach is good. I think that better approach exists for it. <a href="https://apiblueprint.org/">apiblueprint</a> is simple yaml structure than swagger&rsquo;s yaml. but I have not found good <a href="https://apiblueprint.org/">apiblueprint</a> utils for my taste for golang code generation or spec generation from code.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Releasing with bumpversion, govvv and drone</title>
      <link>https://blog.anarcher.dev/post/2017/12-05-release-with-bumpversion-govvv-drone/</link>
      <pubDate>Tue, 05 Dec 2017 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2017/12-05-release-with-bumpversion-govvv-drone/</guid>
      <description>&lt;p&gt;One of pleasures about coding is using good tools. Recently I use &lt;a href=&#34;https://github.com/peritus/bumpversion&#34;&gt;bumpversion&lt;/a&gt;, &lt;a href=&#34;https://github.com/ahmetb/govvv&#34;&gt;govvv&lt;/a&gt; and &lt;a href=&#34;https://github.com/drone/drone&#34;&gt;drone&lt;/a&gt; for version releasing.&lt;/p&gt;
&lt;h2 id=&#34;bumpversion&#34;&gt;bumpversion&lt;/h2&gt;
&lt;p&gt;bumpversion is automation for semantic versioning. Most of my projects have simple config file like below. (.bumpversion.cfg)&lt;/p&gt;






&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[bumpversion]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;commit = True
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tag = True
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;current_version = 0.8.4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parse = (?P&amp;lt;major&amp;gt;\d+)\.(?P&amp;lt;minor&amp;gt;\d+)\.(?P&amp;lt;patch&amp;gt;\d+)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;serialize = 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{major}.{minor}.{patch}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[bumpversion:file:VERSION]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before release,I just run like below:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>One of pleasures about coding is using good tools. Recently I use <a href="https://github.com/peritus/bumpversion">bumpversion</a>, <a href="https://github.com/ahmetb/govvv">govvv</a> and <a href="https://github.com/drone/drone">drone</a> for version releasing.</p>
<h2 id="bumpversion">bumpversion</h2>
<p>bumpversion is automation for semantic versioning. Most of my projects have simple config file like below. (.bumpversion.cfg)</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>[bumpversion]
</span></span><span style="display:flex;"><span>commit = True
</span></span><span style="display:flex;"><span>tag = True
</span></span><span style="display:flex;"><span>current_version = 0.8.4
</span></span><span style="display:flex;"><span>parse = (?P&lt;major&gt;\d+)\.(?P&lt;minor&gt;\d+)\.(?P&lt;patch&gt;\d+)
</span></span><span style="display:flex;"><span>serialize = 
</span></span><span style="display:flex;"><span>	{major}.{minor}.{patch}
</span></span><span style="display:flex;"><span>[bumpversion:file:VERSION]</span></span></code></pre></div>
<p>Before release,I just run like below:</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>bumpversion minor # or major or patch</span></span></code></pre></div>
<p>This update minor version number in VERSION file. (In this case, <code>0.8,4</code> -&gt; <code>0.9.0</code>)
And I configure <code>commit=True</code> and <code>tag=True</code> in .bumpversion.cfg,The <a href="https://github.com/peritus/bumpversion">bumpversion</a> makes a commit and tag.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>commit 243ccf6932d97a3d100de5a2a7b102e1b2dc8cb2 (tag: v0.0.2)
</span></span><span style="display:flex;"><span>Author: anarcher
</span></span><span style="display:flex;"><span>Date:   Tue Dec 5 21:09:21 2017 +0900
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Bump version: 0.0.1 → 0.0.2
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>commit 9e8ff3f08a1039cc10d93749aa805e939cf28f73 (tag: v0.0.1)
</span></span><span style="display:flex;"><span>Author: anarcher
</span></span><span style="display:flex;"><span>Date:   Tue Dec 5 21:08:17 2017 +0900
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Bump version: 0.0.0 → 0.0.1</span></span></code></pre></div>
<h2 id="govvv">govvv</h2>
<p><a href="https://github.com/ahmetb/govvv">govvv</a> is go binary versioning tool that wraps the go build command. Go provides access to setting variables by compile time linker flags. <a href="https://github.com/ahmetb/govvv">govvv</a> provides easy versioning for go versioning even I don&rsquo;t know that <code>--ldflag</code> of <code>go build</code>.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>govvv install -pkg github.com/pkg/version github.com/cmd/</span></span></code></pre></div>
<p>I just created version/version.go</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-gdscript3" data-lang="gdscript3"><span style="display:flex;"><span>package version
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">var</span> (
</span></span><span style="display:flex;"><span>	Version, GitCommit, GitState, BuildDate string
</span></span><span style="display:flex;"><span>)</span></span></code></pre></div>
<p>Because I make new <code>VERSION</code> file with <a href="https://github.com/peritus/bumpversion">bumpversion</a>, <a href="https://github.com/ahmetb/govvv">govvv</a> adds a Version variable from <code>VERSION</code> file to my version package.
I like to seperate version variable with main.go. version variable can be used in another ways. (e.g. metric labels, api version call..)</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>$cmd -v
</span></span><span style="display:flex;"><span>Cmd version 0.8.4 git=2639d4e build=2017-12-05T15:57:13Z</span></span></code></pre></div>
<h2 id="drone">drone</h2>
<p><a href="https://github.com/drone/drone">drone</a> is an open source continuous delivery tool. Interesting features of <a href="https://github.com/drone/drone">drone</a> are that all tasks in drone is docker containers and drone&rsquo;s yaml configure file is a superset  of docker-compose configure file.</p>






<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>clone:
</span></span><span style="display:flex;"><span>    git:
</span></span><span style="display:flex;"><span>        image: plugins/git
</span></span><span style="display:flex;"><span>        network_mode: host
</span></span><span style="display:flex;"><span>        depth: 1
</span></span><span style="display:flex;"><span>pipeline:
</span></span><span style="display:flex;"><span>    test:
</span></span><span style="display:flex;"><span>        image: golang:1.7.1
</span></span><span style="display:flex;"><span>        commands:
</span></span><span style="display:flex;"><span>            - make deps
</span></span><span style="display:flex;"><span>            - make test
</span></span><span style="display:flex;"><span>            - make test-ci
</span></span><span style="display:flex;"><span>    docker:
</span></span><span style="display:flex;"><span>        image: plugins/docker
</span></span><span style="display:flex;"><span>        dockerfile: Dockerfile
</span></span><span style="display:flex;"><span>        repo: app 
</span></span><span style="display:flex;"><span>        force_tag: true
</span></span><span style="display:flex;"><span>        tags: ${DRONE_TAG}
</span></span><span style="display:flex;"><span>        when:
</span></span><span style="display:flex;"><span>            event: tag
</span></span><span style="display:flex;"><span>    slack:
</span></span><span style="display:flex;"><span>        image: plugins/slack
</span></span><span style="display:flex;"><span>        webhook: https://hooks.slack.com/
</span></span><span style="display:flex;"><span>        when:
</span></span><span style="display:flex;"><span>            status: [ success, failure ]</span></span></code></pre></div>
<p>If repository <strong>tag</strong> hooks is enable in drone settings (default disable),git commit tag will sync up with docker tag.
This is simply how to use the tools for releasing and versioning.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Using docker-machine</title>
      <link>https://blog.anarcher.dev/post/2015/09-14-docker-machine/</link>
      <pubDate>Mon, 14 Sep 2015 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2015/09-14-docker-machine/</guid>
      <description>&lt;p&gt;The Docker machine is a command tool created by  the docker team to manage docker servers. It automatically creates hosts and installs docker engine on them and configures the docker client to talk.&lt;/p&gt;
&lt;p&gt;If you install the docker machine tool,you can use it like below:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The Docker machine is a command tool created by  the docker team to manage docker servers. It automatically creates hosts and installs docker engine on them and configures the docker client to talk.</p>
<p>If you install the docker machine tool,you can use it like below:</p>
<pre><code>$docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                        SWARM
host1            generic      Running   tcp://192.168.99.100:2376   host1 (master)
host2            generic      Running   tcp://192.168.99.101:2376   host1
host3            generic      Running   tcp://192.168.99.102:2376   host1
demo0            virtualbox   Stopped                              
demo1            virtualbox   Stopped                              
demo2            virtualbox   Stopped                              
demo3            virtualbox   Stopped                              
infra            virtualbox   Stopped      

$docker-machine ssh host1
...


$docker $(docker-machine config host1) ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
ea13099c15d3        swarm:latest        &quot;/swarm join --addr 1&quot;   7 weeks ago         Up 4 days           2375/tcp            swarm-agent

...
</code></pre>
<p>It&rsquo;s useful to use docker command with docker machine command to connect docker engine on multi hosts.</p>
<p><code>docker-machine config</code> is just printed like below.</p>
<pre><code>$docker-machine config host1
--tlsverify --tlscacert=&quot;/home/anarcher/.docker/machine/machines/host1/ca.pem&quot; 
--tlscert=&quot;/home/anarcher/.docker/machine/machines/host1/cert.pem&quot; 
--tlskey=&quot;/home/anarcher/.docker/machine/machines/host1/key.pem&quot; -H=tcp://192.168.99.100:2376
</code></pre>
<p>As you know,the bash command substitution can make the output of docker-machine command to replace the command itself. It&rsquo;s one of the funny things using unix shell, too. :-)</p>
<p>Docker machine keeps the configuraion files which are  information to connect on docker hosts to ~/.docker/machine/. If you want to share it with the others,you just copy it and share it.</p>
<p>Docker machine is based on ssh authentication to set up docker host nodes. So you can log in hosts to use <code>docker-machine ssh [name]</code>.</p>
<p>Docker machine has many drivers that represent the virtual environments.The virtual environments are local linux,AWS,Digital ocean and many more.  You can also add a existed Docker host to use driver <code>none</code> or if the host doesn&rsquo;t has a docker engine,you can use the driver <code>generic</code> to install docker engine.</p>
<p>Docker machine has many options. So I have been using  <code>grep</code> command with Unix pipe for searching the right command.</p>
<pre><code>$docker-machine create -h | grep digi
   --digitalocean-access-token              Digital Ocean access token [$DIGITALOCEAN_ACCESS_TOKEN]
   --digitalocean-backups                   enable backups for droplet [$DIGITALOCEAN_BACKUPS]
   --digitalocean-image &quot;ubuntu-14-04-x64&quot;  Digital Ocean Image [$DIGITALOCEAN_IMAGE]
   --digitalocean-ipv6                      enable ipv6 for droplet [$DIGITALOCEAN_IPV6]
   --digitalocean-private-networking        enable private networking for droplet [$DIGITALOCEAN_PRIVATE_NETWORKING]
   --digitalocean-region &quot;nyc3&quot;             Digital Ocean region [$DIGITALOCEAN_REGION]
   --digitalocean-size &quot;512mb&quot;              Digital Ocean size [$DIGITALOCEAN_SIZE]
</code></pre>
<p>Basically It&rsquo;s a convenience tool which looks like other docker tools. But unlike <code>ansible</code> or <code>chef</code>, It only care for Docker engine. If you want to host configuration, You should use other tools with <code>docker-machine</code>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>About Docker Swarm</title>
      <link>https://blog.anarcher.dev/post/2015/02-14-about-docker-swarm/</link>
      <pubDate>Sat, 14 Feb 2015 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2015/02-14-about-docker-swarm/</guid>
      <description>&lt;p&gt;오랜만에 &lt;code&gt;docker-korea&lt;/code&gt; &lt;a href=&#34;http://onoffmix.com/event/40731&#34;&gt;meetup&lt;/a&gt;에서 &lt;a href=&#34;speakerdeck.com/anarcher/about-docker-swarm&#34;&gt;About Docker Swarm&lt;/a&gt;이라는 이름으로 작은 발표를 했다.&lt;/p&gt;
&lt;p&gt;장표는 매우 간단하게 구성하고 데모에서 많은 이야기를 하고 싶었는데. 프로젝터설정부터 힘들어서 준비했던것을 절반밖에 이야기하지 못한것 같다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Docker Swarm&lt;/code&gt;은 다른 클러스텅 시스템과 다른 부분들이 있다. 가장 큰 다른 점은 &lt;code&gt;Docker&lt;/code&gt;에서 만들었다는 것. 즉 &lt;code&gt;coreos/fleet&lt;/code&gt;이 &lt;code&gt;Distributed Init System&lt;/code&gt;을 표방하는 것과 비슷하게 &lt;code&gt;Swarm&lt;/code&gt;은 &lt;code&gt;Docker-native Clustering System&lt;/code&gt;을 이야기한다. &lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>오랜만에 <code>docker-korea</code> <a href="http://onoffmix.com/event/40731">meetup</a>에서 <a href="speakerdeck.com/anarcher/about-docker-swarm">About Docker Swarm</a>이라는 이름으로 작은 발표를 했다.</p>
<p>장표는 매우 간단하게 구성하고 데모에서 많은 이야기를 하고 싶었는데. 프로젝터설정부터 힘들어서 준비했던것을 절반밖에 이야기하지 못한것 같다.</p>
<p><code>Docker Swarm</code>은 다른 클러스텅 시스템과 다른 부분들이 있다. 가장 큰 다른 점은 <code>Docker</code>에서 만들었다는 것. 즉 <code>coreos/fleet</code>이 <code>Distributed Init System</code>을 표방하는 것과 비슷하게 <code>Swarm</code>은 <code>Docker-native Clustering System</code>을 이야기한다. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>즉 다음과 같은 확장으로 <code>Docker</code> Interface(CLI/API)을 유지하고 싶어 한다.</p>
<pre><code>docker run -d nginx-logger -e affinity:container==nginx nginx-logger
</code></pre>
<p>Google의 <code>k8s</code>나 다른 클러스트링 도구는 각자 자신만의 개념과 그 개념의 이해를 사용자에게 수반하게 만드는데. <code>Swarm</code>의 가장 큰 장점은 이러한 학습을 최소화 할수 있다는 점이 아닐까 싶기도 하다. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>물론 이러한 접근이 쉽게 풀수 있는 문제를 어렵게 풀수 있는 여지가 있기도 하다.</p>
<p>개인적으로는 <code>Docker</code>의 성공이 기술이 아니라 일종의 사용성에 기인한거라면 <code>Swarm</code>도 이러한 장점을 잘 이해하고 있다는 생각도 든다.</p>
<p>ps) 하지만 아직 <code>0.1.0 (HEAD)</code>이고 프로덕션에서 쓰기에는 어리다.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>우리가 무언가 만들때 발생할수 밖에 없는 개념들이 실제 문제의 해결이 아니라 또 다른 문제를 야기할수도 있다는 생각도 들고, <code>coreos</code>은 <code>Unix</code>가 가지고 있는 개념을 확장하고 싶어하는 느낌이다.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>물론 <code>k8s</code>의 Pod라는 개념은 나쁘지 않다.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>Vengo 사용하기</title>
      <link>https://blog.anarcher.dev/post/2014/12-20-using-vengo/</link>
      <pubDate>Sat, 20 Dec 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/12-20-using-vengo/</guid>
      <description>&lt;p&gt;Python을 사용하는 사람이라면, virtualenv을 잘 알것이다. 각 프로그램마다 각자의 파이썬 환경을 구성할수 있는 도구이다. (Py3에 기본으로 추가되어 있다)&lt;/p&gt;
&lt;p&gt;go tool은 개인적으로 불만이 많은 도구이다. 특히 go get은 여러가지 기능의 부족으로 당황스러움을 느끼게 한다.&lt;/p&gt;
&lt;p&gt;가령 go get은 scm(git,hg&amp;hellip;)에서 직접 가져온다. 하지만 언제나 master branch의 최신을 가져온다. 즉 버져닝(versioning)에 대한 부분이 없다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Python을 사용하는 사람이라면, virtualenv을 잘 알것이다. 각 프로그램마다 각자의 파이썬 환경을 구성할수 있는 도구이다. (Py3에 기본으로 추가되어 있다)</p>
<p>go tool은 개인적으로 불만이 많은 도구이다. 특히 go get은 여러가지 기능의 부족으로 당황스러움을 느끼게 한다.</p>
<p>가령 go get은 scm(git,hg&hellip;)에서 직접 가져온다. 하지만 언제나 master branch의 최신을 가져온다. 즉 버져닝(versioning)에 대한 부분이 없다.</p>
<p>그리고 go get은 상대경로에 대한 인식을 하지 않는다. 언제나 $GOPATH부터 절대 경로로 패캐지를 임포트해야 한다. (언어의 제안사항이 아님)</p>
<p>go get에 특정 브랜치나 특정 태그(버젼)을 추가하자는 이야기는 go-nuts에 많이 (주기적으로) 나오는 이야기로 알고 있다.</p>
<p>개인적인 생각으로는 특히  오픈소스에서 버젼은 일종의 대화의 좋은 재료라고 생각한다. 구글안에서 처럼 항상 master branch가 stable하다고 하기에는 힘들다.</p>
<p>원래 하려는 이야기는 Versioning이 아니었는데.하튼
<a href="github.com/icub3d/goblog">Vengo</a>는 Python의 virtualenv처럼 여러 Go환경을 구성할수 있는 프로젝트이다.</p>
<p><img src="/img/post/2014-12-vengo.png" alt="VengoImage1"></p>
<p>Vengo은 Go 자체도 설치해준다.</p>
<p><code>vengo install -b 1.4</code></p>
<p>Python virtualenv 에 친숙하다면, 그리 어렵지 않게 사용할수 있을것 같다.</p>
<p>하나 궁금한 점은 이미 만들어진 환경에 go의 버젼을 변경할수 있는지이다.
(다시 만들어도 되겠지만)</p>
<p>Go에서 외부 라이브러리 의존성 관리를 위해 여러 도구들이 있지만. 여러 오픈소스에서 가장 많이 사용하는 도구는 아마 Kz가 만든  <a href="http://github.com/tools/godep">godep</a> 일것이다.</p>
<p>godep은 현재 패캐지와 의존성이 있는 패캐지들의 정보를 Godeps 디렉토리에  json포맷으로 저장하고 관련 패캐지들을 Godeps/.workspace에 복사한다.</p>
<p>godep을 사용하는 많은 프로젝트가 사용하는 외부 패캐지들을 이렇게 자신의 git 저장소에 저장해서 사용한다.  <a href="https://github.com/GoogleCloudPlatform/kubernetes">GoogleCloudPlatform/kubernetes</a> , <a href="https://github.com/coreos/etcd">codeos/etcd</a></p>
<p>Vengo랑 함께 사용하면 Godep으로 vendoring되어 있는 패캐지들은 현재 환경에 <code>godep restore</code>해서 사용하고 변경된 현재 환경을 <code>godep save</code>해서 사용할수 있다.</p>
<p>요즘 내가 사용하는 방식이다.</p>
<p>godep에서 외부 패캐지를 다 내 저장소에 저장하는 것에 대한 것이 scm을 일종의 디스크로 사용하는 느낌이라서 좋은 방법이 아니지 않나 하는 생각도 든다.</p>
<p>즉 npm이나 rubygem이나 docker registry처럼 scm와 연동된 패캐지 호스팅 서비스등이 있어야 하지 않나 라는 생각인데. Go에서도 비슷한 시도가 있었지만 대중적으로 인기가 있진 않다.
(링크를 찾지 못하겠다.)</p>
<p>오픈소스 커뮤니티에서 여러가지 시도가 있으며, Python virtualenv 처럼 정리되어 go tool에 좋은 것이 포함되었으면 싶다. (<em>다양성과 효율성</em>이란 시점에서도 이런 움직임이 있어야 한다고 생각한다.)</p>
<ul>
<li><a href="https://github.com/golang/go/wiki/PackageManagementTools">PackageManagementTools</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Docker deployment slide</title>
      <link>https://blog.anarcher.dev/post/2014/06-19-docker-deployment/</link>
      <pubDate>Thu, 19 Jun 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/06-19-docker-deployment/</guid>
      <description>&lt;p&gt;사내에서 Docker 사용에 대한 이야기가 나와서 간단하게 조사해보았다.
매력적인 프로젝트인것은 확실하지만, 기존에 chef나 opsworks로 구성되어 있는 부분도 있고 현재 시스템 구조상
docker으로 이전해서의 이득이 생각외로 크지 않다는 것이 중평.&lt;/p&gt;
&lt;p&gt;docker의 장점은 대개 두가지로 이야기 할수 있겠다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Portability (이식성)&lt;/li&gt;
&lt;li&gt;Repeatability (반복성)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이식성(Portability)은 가장 크게 얻는 이점은  개발환경과 실제 프로덕션 환경의 차이를 설정변수 몇개로 축소할수 있다는 점이라고 생각한다.
여러 환경(개발,테스트,프로덕션)을 일치시키기 위한 별다른 노력을 할 필요 없다는 점이 가장 큰 매력으로 생각한다.
물론 자바와 비슷하게 한번 작성하면 어디서든 동작한다는 것이 여러 Host 환경에서 동작할 수 있다는 점도 무시할수는 없겠다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>사내에서 Docker 사용에 대한 이야기가 나와서 간단하게 조사해보았다.
매력적인 프로젝트인것은 확실하지만, 기존에 chef나 opsworks로 구성되어 있는 부분도 있고 현재 시스템 구조상
docker으로 이전해서의 이득이 생각외로 크지 않다는 것이 중평.</p>
<p>docker의 장점은 대개 두가지로 이야기 할수 있겠다.</p>
<ul>
<li>Portability (이식성)</li>
<li>Repeatability (반복성)</li>
</ul>
<p>이식성(Portability)은 가장 크게 얻는 이점은  개발환경과 실제 프로덕션 환경의 차이를 설정변수 몇개로 축소할수 있다는 점이라고 생각한다.
여러 환경(개발,테스트,프로덕션)을 일치시키기 위한 별다른 노력을 할 필요 없다는 점이 가장 큰 매력으로 생각한다.
물론 자바와 비슷하게 한번 작성하면 어디서든 동작한다는 것이 여러 Host 환경에서 동작할 수 있다는 점도 무시할수는 없겠다.</p>
<p>반복성(Repeatability)은 결국 컨테이너와 이미지를 생성/변경/실행이 빠르고 가볍기 때문에 지속적인 통합(Continuous Integration)과 배포(Deployment) 이득이 있다.</p>
<p>아래 장표에서 밴치마크 부분은 docker 0.7/linux 3.8 기준으로 작성되어 있는 것을 참고했다. linux 3.11에서 network부분의 향상이 있어서 지금 docker 1.0/linux 3.11 에서의 network 성능은 Host와의 차이가 크지 않을 것이라고 생각한다. (자료를 찾아보거나 테스트해 볼 필요는 있어보인다)</p>
<iframe src="//slides.com/anarcher/docker-deployment/embed" width="576" height="420" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
]]></content:encoded>
    </item>
    <item>
      <title>Send-to-kindle 2014-05</title>
      <link>https://blog.anarcher.dev/post/2014/05-send-to-kindle/</link>
      <pubDate>Sat, 10 May 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/05-send-to-kindle/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;읽어야 할 글들을 Kindle에 던지는데,뭘 킨들에 던졌는지 기록해 두면 좋을 것 같아서 적어본다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;gos-power-is-in-emergent-behavior&#34;&gt;Go&amp;rsquo;s power is in emergent behavior&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.onebigfluke.com/2014/04/gos-power-is-in-emergent-behavior.html&#34;&gt;http://www.onebigfluke.com/2014/04/gos-power-is-in-emergent-behavior.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;golang의 interface의 특징을 두가지 예(http.HandlerFunc,opaque type)을 가지고 설명.
저번에 있었던 gophercon에서 들은 내용에 대한 글.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;go-parallel-12&#34;&gt;Go Parallel 1,2&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://software.intel.com/en-us/blogs/2013/06/18/go-parallel&#34;&gt;https://software.intel.com/en-us/blogs/2013/06/18/go-parallel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://software.intel.com/en-us/blogs/2014/04/13/go-parallel-2&#34;&gt;https://software.intel.com/en-us/blogs/2014/04/13/go-parallel-2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;고루틴에 대한 예제와 함께 짧게 고루틴을 알수 있는 글.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;go-best-practices-for-production-environments&#34;&gt;Go: Best Practices for Production Environments&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;http://peter.bourgon.org/go-in-production/&#34;&gt;http://peter.bourgon.org/go-in-production/&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>읽어야 할 글들을 Kindle에 던지는데,뭘 킨들에 던졌는지 기록해 두면 좋을 것 같아서 적어본다.</p></blockquote>
<h2 id="gos-power-is-in-emergent-behavior">Go&rsquo;s power is in emergent behavior</h2>
<ul>
<li><a href="http://www.onebigfluke.com/2014/04/gos-power-is-in-emergent-behavior.html">http://www.onebigfluke.com/2014/04/gos-power-is-in-emergent-behavior.html</a></li>
<li>golang의 interface의 특징을 두가지 예(http.HandlerFunc,opaque type)을 가지고 설명.
저번에 있었던 gophercon에서 들은 내용에 대한 글.</li>
</ul>
<h2 id="go-parallel-12">Go Parallel 1,2</h2>
<ul>
<li><a href="https://software.intel.com/en-us/blogs/2013/06/18/go-parallel">https://software.intel.com/en-us/blogs/2013/06/18/go-parallel</a></li>
<li><a href="https://software.intel.com/en-us/blogs/2014/04/13/go-parallel-2">https://software.intel.com/en-us/blogs/2014/04/13/go-parallel-2</a></li>
<li>고루틴에 대한 예제와 함께 짧게 고루틴을 알수 있는 글.</li>
</ul>
<h2 id="go-best-practices-for-production-environments">Go: Best Practices for Production Environments</h2>
<ul>
<li>
<p><a href="http://peter.bourgon.org/go-in-production/">http://peter.bourgon.org/go-in-production/</a></p>
</li>
<li>
<p>soundcloud에서 go 프로젝트를 하면서 생긴 팁들을 나열.</p>
</li>
<li>
<p>개인적으로는 python의 virtualenv처럼 여러 GOPATH을 관리 할 수 있으면 좋겠다.
(아마 이미 관련 도구가 있을 듯 하기도 하다.)</p>
</li>
</ul>
<h2 id="why-i-like-go">Why I like Go?</h2>
<ul>
<li><a href="https://gist.github.com/freeformz/4746274">https://gist.github.com/freeformz/4746274</a></li>
<li><a href="https://news.ycombinator.com/item?id=5195257">https://news.ycombinator.com/item?id=5195257</a></li>
</ul>
<h2 id="the-case-for-reactjs-and-clojurescript">The Case for React.js and ClojureScript</h2>
<ul>
<li>
<p><a href="http://murilopereira.com/the-case-for-reactjs-and-clojurescript/#/">http://murilopereira.com/the-case-for-reactjs-and-clojurescript/#/</a></p>
</li>
<li>
<p>react.js와 clojurescript에 대한 이야기.</p>
</li>
<li>
<p>react.js은 거칠게 이야기해서 MVC중 V에 해당한다.</p>
</li>
<li>
<p>개인적으로 관심을 가지고 있는 프론트엔드 프로젝트중 하나.</p>
</li>
</ul>
<h2 id="load-balancing-with-vulcan-and-etcd">Load balancing with Vulcan and Etcd</h2>
<ul>
<li>
<p><a href="http://vulcan.ghost.io/intro/">http://vulcan.ghost.io/intro/</a></p>
</li>
<li>
<p>docker을 만든 dotcloud의 <a href="https://github.com/dotcloud/hipache">https://github.com/dotcloud/hipache</a>는  redis을 backend data로 사용하는데 반해,</p>
</li>
<li>
<p>vulcan은 etcd에 있는 데이터를 기반으로 동적으로 로드밸랜싱을 해주는 리버스 프록시 프로젝트이다.</p>
</li>
<li>
<p>go로 만든 프로젝트.</p>
</li>
</ul>
<h2 id="why-we-dont-hire-programmers-based-on-puzzles-api-quizzes-math-riddles-or-other-parlor-tricks">Why we don&rsquo;t hire programmers based on puzzles, API quizzes, math riddles, or other parlor tricks</h2>
<ul>
<li>
<p><a href="http://signalvnoise.com/posts/3071-why-we-dont-hire-programmers-based-on-puzzles-api-quizzes-math-riddles-or-other-parlor-tricks">http://signalvnoise.com/posts/3071-why-we-dont-hire-programmers-based-on-puzzles-api-quizzes-math-riddles-or-other-parlor-tricks</a></p>
</li>
<li>
<p><a href="http://gettingreal.37signals.com/ch08_Kick_the_Tires.php">http://gettingreal.37signals.com/ch08_Kick_the_Tires.php</a></p>
</li>
<li>
<p>실제 코드와 이슈로 좋은 프로그래머를 찾는 것이 특정 퀴즈로 찾는 것보다 성공률이 높다.</p>
</li>
<li>
<p>함께 일해보는 것 만큼 좋은 인터뷰는 없다.</p>
</li>
</ul>
<h1 id="immutable-infrastructure-with-ansible-and-packer">Immutable Infrastructure with Ansible and Packer</h1>
<ul>
<li><a href="http://blog.codeship.io/2014/05/08/ansible-packer-immutable-infrastructure.html">http://blog.codeship.io/2014/05/08/ansible-packer-immutable-infrastructure.html</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Computer network Coursera course</title>
      <link>https://blog.anarcher.dev/post/2014/05-01-coursera-network/</link>
      <pubDate>Thu, 01 May 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/05-01-coursera-network/</guid>
      <description>&lt;img src=&#34;https://blog.anarcher.dev/img/post/network-soa.jpg&#34; /&gt;
&lt;p&gt;나름 고생스러워서 기록삼아 포스팅.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<img src="/img/post/network-soa.jpg" />
<p>나름 고생스러워서 기록삼아 포스팅.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Send-to-kindle 2014-04</title>
      <link>https://blog.anarcher.dev/post/2014/04-send-to-kindle/</link>
      <pubDate>Thu, 03 Apr 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/04-send-to-kindle/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;읽어야 할 글들을 Kindle에 던지는데,뭘 킨들에 던졌는지 기록해 두면 좋을 것 같아서 적어본다.
이번달은 읽은 글들이 많지가 않다. T_T&lt;/p&gt;&lt;/blockquote&gt;
&lt;h1 id=&#34;go-and-package-versioning&#34;&gt;Go and Package Versioning&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://zduck.com/2014/go-and-package-versioning/&#34;&gt;http://zduck.com/2014/go-and-package-versioning/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;My dream is for go get to support a version number component in the import path. So github.com/jpoehls/gophermail would fetch the HEAD of the repository as it does today. github.com/jpoehls/gophermail#v1 would fetch the v1 branch or tag.&amp;rdquo;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>읽어야 할 글들을 Kindle에 던지는데,뭘 킨들에 던졌는지 기록해 두면 좋을 것 같아서 적어본다.
이번달은 읽은 글들이 많지가 않다. T_T</p></blockquote>
<h1 id="go-and-package-versioning">Go and Package Versioning</h1>
<ul>
<li><a href="http://zduck.com/2014/go-and-package-versioning/">http://zduck.com/2014/go-and-package-versioning/</a></li>
</ul>
<blockquote>
<p>&ldquo;My dream is for go get to support a version number component in the import path. So github.com/jpoehls/gophermail would fetch the HEAD of the repository as it does today. github.com/jpoehls/gophermail#v1 would fetch the v1 branch or tag.&rdquo;</p></blockquote>
<p><a href="http://gopkg.in">http://gopkg.in</a> 을 사용하면 github에 한해, branch,tag로 구분되어 있는 버젼을 패캐지버젼을 사용할수 있게 된다.</p>
<p>일반적으로 버젼이 존재함에 있어서 생기는 문제가 있어서 go tools에서 버젼을 지원하지 않는 것은 감정적으로는 조금은 무책임하다고 생각한다.  저자처럼 go get에서 branch나 tag을 지원해주는 정도는 무난하지 않나 싶기도 하다.</p>
<p>지금 go get은  branch나 tag을 go version에 대응해서 사용하고 있다.</p>
<h1 id="write-code-every-day">Write code every day</h1>
<ul>
<li><a href="http://ejohn.org/blog/write-code-every-day/">http://ejohn.org/blog/write-code-every-day/</a></li>
</ul>
<p>&ldquo;the feeling of making progress is just as important as making actual progress. &quot; - Inspirational blog post</p>
<h1 id="throttled-guardian-of-the-web-server">Throttled: Guardian Of The Web Server</h1>
<ul>
<li><a href="http://0value.com/throttled--guardian-of-the-web-server">http://0value.com/throttled--guardian-of-the-web-server</a></li>
</ul>
<p>http  요청 접근에 대한 여러가지 방법(rate-limiting,메모리 사용에 대한 요청에 허가 등)을 구현한 라이브러리.</p>
<p>go 표준 라이브러리인 http.Handler에 적용해서 사용할수 있다</p>
<h1 id="go-concurrency-patterns-pipelines-and-cancellation">Go Concurrency Patterns: Pipelines and cancellation</h1>
<ul>
<li><a href="http://blog.golang.org/pipelines">http://blog.golang.org/pipelines</a></li>
</ul>
<p>goroutine은 동시성을 얻기 위한 언어도구이다. 각 단계가 독립적으로 각 입력과 출력을 다른 동시성을 가지고 있는 파이프라인을 고루틴으로 가지고 어떻게 구성하는지와 동작의 취소에 대한 구현방법 이야기.</p>
<h1 id="defining-http-status-codes">Defining HTTP Status Codes</h1>
<ul>
<li><a href="http://refugeeks.com/defining-http-status-codes-list-http-status-codes/">http://refugeeks.com/defining-http-status-codes-list-http-status-codes/</a> : Defining HTTP Status Codes</li>
</ul>
<p>고양이 사진으로 보는 http 상태 코드들.</p>
<h1 id="some-thoughts-on-go-and-erlang">Some Thoughts on Go and Erlang</h1>
<ul>
<li><a href="http://blog.erlware.org/2014/04/27/some-thoughts-on-go-and-erlang/">http://blog.erlware.org/2014/04/27/some-thoughts-on-go-and-erlang/</a></li>
</ul>
<p>제목과 달리 (Erlang에 비해) Go의 단점에 대한 이야기.
결론적으로 결함 감내(Fault tolerant )와 낮은 지연 시간(low latency)에 Go가 적합하지 않다는 내용.</p>
<p>Fault tolerant이 필요한 복잡한 시스템에서   Erlang에 비해 상태를 공유하는 다른 언어처럼 쉽게 망가지고,   Go의 현재 GC가 Global mark-and-sweep이기 때문에  Low latency을 얻기 힘든다는 내용이다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Send-to-kindle 2014-03</title>
      <link>https://blog.anarcher.dev/post/2014/03-send-to-kindle/</link>
      <pubDate>Tue, 11 Mar 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/03-send-to-kindle/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;읽어야 할 글들을 Kindle에 던지는데,뭘 킨들에 던졌는지 기록해 두면 좋을 것 같아서 적어본다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h1 id=&#34;why-atom-cant-replace-vim--learning-the-lesson-of-vi&#34;&gt;&lt;a href=&#34;https://medium.com/p/433852f4b4d1&#34;&gt;Why Atom Can’t Replace Vim : Learning the lesson of vi&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Atom이 Emacs의 확장가능성은 가질수 있지만, Vi의 조합가능성에 대해서는 배운 바가 없다는 글.&lt;/p&gt;
&lt;p&gt;조합가능성에 대한 글로는
&lt;a href=&#34;http://blog.dahlia.kr/post/78940164278&#34;&gt;http://blog.dahlia.kr/post/78940164278&lt;/a&gt; 홍민희님의 글과 함께 보면 좋다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>읽어야 할 글들을 Kindle에 던지는데,뭘 킨들에 던졌는지 기록해 두면 좋을 것 같아서 적어본다.</p></blockquote>
<h1 id="why-atom-cant-replace-vim--learning-the-lesson-of-vi"><a href="https://medium.com/p/433852f4b4d1">Why Atom Can’t Replace Vim : Learning the lesson of vi</a></h1>
<p>Atom이 Emacs의 확장가능성은 가질수 있지만, Vi의 조합가능성에 대해서는 배운 바가 없다는 글.</p>
<p>조합가능성에 대한 글로는
<a href="http://blog.dahlia.kr/post/78940164278">http://blog.dahlia.kr/post/78940164278</a> 홍민희님의 글과 함께 보면 좋다.</p>
<p>내가 생각하는 조합 가능성은  명령어들의 조합이 명령어와 차별 받지 않고 같은 취급을 받는 것이 아닌가 싶다. 유닉스의 파이프로 연결하여 또 하나의 명령어를 만들듯이.</p>
<p>또 하나의 생각은 Emacs은 어떤 기능이 필요할때 플러그인으로 확장해서 기능을 구현하지만, Vi은 외부 명령어와의 조합으로 기능을 구현한다라는 점.</p>
<h1 id="sane-concurrency-with-go"><a href="https://www.readability.com/articles/mmtzoqbu">Sane Concurrency with Go</a></h1>
<p>공유되는 상태의 병렬로 상태를 바꾸려고 할때, 뮤텍스가 아닌 고루틴과 채널을 이용하여 동기화하는 방법과 디자인에 대한 글</p>
<p>상태를 가지고 있는 객체 내부에 하나의 고루틴  이벤트 루프를 두어서 동기화를 하고,버퍼가 없는 채널을 이용하는 메소드 인터페이스를 구성하여, 외부에서는 간단히  일반적인 호출을 하는 디자인을 설명.</p>
<p>Heka의 기본적인 디자인 패턴이기도 함.</p>
<p>TwistedPython의 저자 Glyph의 Unyielding에 있는 계좌이체 예제를 Go언어의 고루틴과 채널을 이용하여 구현하는 방법에 대한 글.</p>
<h1 id="unyielding"><a href="https://glyph.twistedmatrix.com/2014/02/unyielding.html">Unyielding</a></h1>
<p>TwistedPython의 저자 Glyph의 동시성에 대한 글.</p>
<h1 id="why-threads-are-a-bad-idea-for-most-purposes"><a href="http://www.stanford.edu/~ouster/cgi-bin/papers/threads.pdf">Why Threads Are A Bad Idea (for most purposes)</a></h1>
<p>대부분의 경우 쓰레드가 왜 나쁜 아이디어인지에 대한 키노트.</p>
<p>많은 경우 쓰레드보다는 이벤트 방식이 좀더 유용하다. (GUI 이벤트,분산 시스템 등등..)
쓰레드가 이벤트보다 강력하지만 그 만큼 위험하다.
쓰레드는 CPU기반 동시성이 필요할때만 사용하자.</p>
<h1 id="etcd--ansible--crazy-delicious"><a href="http://www.unicornclouds.com/blog_posts/etcd_ansible_integration">etcd + ansible = crazy delicious</a></h1>
<p>ansible은 기본적으로 파일을 기반으로 접속할 서버를 찾거나 기타 정보를 얻는다.
ansible에서 이러한 정보를 인벤토리라고 부르는데, ansible tower라는 인벤토리 서버와 웹 관리도구을 상용으로 제공하기도 한다.</p>
<p>ansible에는 동적 인벤토리라는 기능을 제공하는데. 이 기능을 이용하여 인벤토리를 etcd에 저장하고 ansible을 사용하는 방법에 대한 글.</p>
<h1 id="datomic-rationale-why-did-we-build-datomic"><a href="http://www.datomic.com/rationale.html">Datomic Rationale Why did we build Datomic?</a></h1>
<p>기존의 데이터베이스는 Client/Server구조를 기본적으로 가진다. Scalability을 위해 Server을 Clustering을 하거나 Sharing,Replicating을 하게 된다.
그리고 Client(Application)에서 일종의 Caching을 구성하게 된다.</p>
<p>Datomic은 이러한 전통적인 데이터베이스의 구성요소를 해체(Deconstruct)해서 다음과 같은 구조로 각 요소에 대한 좀 더  효율성(Efficiency)과 확장성(Scalability)을 구성할수 있도록 한다.</p>
<ul>
<li>Peers : LiveIndex,Local Cache,Query (쿼리 할 때 Live Index,Local cache를 참고한다 (모든 데이터에 대한 캐쉬가 각 Peer에 존재하는 듯 하다(기본적으로))</li>
<li>Transactor : 각 Peer의 Writes에 대한 모든 Transaction을 담당한다.</li>
<li>Storage services : 영속적인 스토리지 서비스에 대한 인터페이스</li>
<li>Cache : Optional</li>
</ul>
<p><img src="http://www.datomic.com/uploads/3/5/9/7/3597326/119999_orig.jpg" alt="img"></p>
<h1 id="building-your-first-app-on-coreos-start-to-finish"><a href="http://www.centurylinklabs.com/building-your-first-app-on-coreos/">BUILDING YOUR FIRST APP ON COREOS: START TO FINISH</a></h1>
<p>mac osx에서 (다른 OS도 가능하겠지만) coreos와 fig등을 이용하여 wordpress을 사용하는 방법을 적은 글.
개인적으로 fleet에 대한 관심이 생기게 된 글이다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>D 언어 사용기</title>
      <link>https://blog.anarcher.dev/post/2014/03-01-hello-world-d/</link>
      <pubDate>Sat, 01 Mar 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/03-01-hello-world-d/</guid>
      <description>&lt;p&gt;아직 서비스에 사용이 가능할지는 미지수이지만, Python으로 구성한 REST API Server을 이번에 D언어로 프로토타이핑을 하게 되었다.&lt;/p&gt;
&lt;p&gt;우선 사용한 라이브러리는 &lt;a href=&#34;http://vibed.org/&#34;&gt;vibe.d&lt;/a&gt;와 Backend Server와의 통신을 위해 &lt;a href=&#34;http://thrift.apache.org/&#34;&gt;thrift&lt;/a&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://vibed.org&#34;&gt;vibe.d&lt;/a&gt;은 기본적으로 &lt;a href=&#34;http://redis.io&#34;&gt;redis&lt;/a&gt;와 &lt;a href=&#34;http://www.mongodb.org/&#34;&gt;mongodb&lt;/a&gt;을 지원하지만, Thrift에 대한 지원은 없다.&lt;/p&gt;
&lt;p&gt;vibed의 &lt;a href=&#34;http://vibed.org/blog/posts/writing-native-db-drivers&#34;&gt;Writing native database drivers - and a new MySQL driver port&lt;/a&gt; 을 참고하여 TSocket을 vibe.d의 TCPConnection을 사용하도록 만들어서 사용했다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>아직 서비스에 사용이 가능할지는 미지수이지만, Python으로 구성한 REST API Server을 이번에 D언어로 프로토타이핑을 하게 되었다.</p>
<p>우선 사용한 라이브러리는 <a href="http://vibed.org/">vibe.d</a>와 Backend Server와의 통신을 위해 <a href="http://thrift.apache.org/">thrift</a>이다.</p>
<p><a href="http://vibed.org">vibe.d</a>은 기본적으로 <a href="http://redis.io">redis</a>와 <a href="http://www.mongodb.org/">mongodb</a>을 지원하지만, Thrift에 대한 지원은 없다.</p>
<p>vibed의 <a href="http://vibed.org/blog/posts/writing-native-db-drivers">Writing native database drivers - and a new MySQL driver port</a> 을 참고하여 TSocket을 vibe.d의 TCPConnection을 사용하도록 만들어서 사용했다.</p>
<p>(지금으로써는) 간단한 REST API Server이라서 언어적인 기능을 많이 사용하지는 않았지만,간단히 D언어 사용에 대한 평을 해보자면,</p>
<ul>
<li>타입시스템에 반하여 암묵적으로 컴파일러가 처리하는 부분이 없다.</li>
<li>함수적 프로그래밍(Functional Programming)위해 만들지 않고, 함수적 프로그래밍의 개념을 절차적인 언어의 기반에서 적절하게 적용했다.</li>
<li>물론 객체지향 프로그래밍을 지원하며, 객체지향적인 프로그래밍에 필요한 참조기반의 의미론과 이에 반해 struct등을 사용한 값기반의 의미론을 모두 지원한다.</li>
<li>가비지콜렉션을 지원하지만, 명시적으로 메모리 할당과 해제를 할수도 있다. (하지만 난 거의 그렇게 사용하지 않았다)</li>
<li>동시성에 대한 설계에서 erlang등의 ActorModel에 영향을 받아서 설계되었다. (하지만 다른 언어처럼 잠금기반의 라이브러리도 지원한다)</li>
</ul>
<p>특히 <a href="http://www.amazon.com/The-Programming-Language-Andrei-Alexandrescu/dp/0321635361">The D Programming language</a> 이 책은 D 언어에 관심이 없더라도, 한번쯤 읽어 볼만 하다.저자가 언어의 디자인 결정을 왜 했는지에 대한 이야기를 정말 재미있게 풀었다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Chromebook for coding</title>
      <link>https://blog.anarcher.dev/post/2014/01-06-chromebook/</link>
      <pubDate>Mon, 06 Jan 2014 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2014/01-06-chromebook/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-ash4/1509213_10152197112323647_1918159647_n.jpg&#34; alt=&#34;enter image description here&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.theverge.com/2013/10/23/4948120/acer-c720-chromebook-review&#34;&gt;크롬북&lt;/a&gt;을 샀다.&lt;/p&gt;
&lt;p&gt;크롬북의 가장 큰 장점은 &lt;strong&gt;가격&lt;/strong&gt;이다. $199에 이정도 노트북을 살수 있다는 것은 분명 매력적.
정말로 크롬 웹 브라우저만 있다. 흠&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;좋지 않은 디스플레이 (흐릿한 디스플레이는 C720의 가장 큰 하드웨어 단점이다)&lt;/li&gt;
&lt;li&gt;8시간 사용 가능한 배터리 (하스웰 기반 CPU이 주는 혜택. 8시간이상 되니까 핸드폰처럼 충전기를 가지고 다니지 않게 되었다)&lt;/li&gt;
&lt;li&gt;내 아이폰과 같은 용량인 16기가 SSD.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;나의 개발환경을 기본적으로 한쪽 화면에 터미널(들),또 다른 화면에는 웹 브라우저(들)뿐이다. 크롬OS는 개발자 모드로 shell을 사용할수 있으므로, 코딩하는게 크게 문제는 없다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://fbcdn-sphotos-b-a.akamaihd.net/hphotos-ak-ash4/1509213_10152197112323647_1918159647_n.jpg" alt="enter image description here"></p>
<p><a href="http://www.theverge.com/2013/10/23/4948120/acer-c720-chromebook-review">크롬북</a>을 샀다.</p>
<p>크롬북의 가장 큰 장점은 <strong>가격</strong>이다. $199에 이정도 노트북을 살수 있다는 것은 분명 매력적.
정말로 크롬 웹 브라우저만 있다. 흠&hellip;</p>
<ul>
<li>좋지 않은 디스플레이 (흐릿한 디스플레이는 C720의 가장 큰 하드웨어 단점이다)</li>
<li>8시간 사용 가능한 배터리 (하스웰 기반 CPU이 주는 혜택. 8시간이상 되니까 핸드폰처럼 충전기를 가지고 다니지 않게 되었다)</li>
<li>내 아이폰과 같은 용량인 16기가 SSD.</li>
</ul>
<p>나의 개발환경을 기본적으로 한쪽 화면에 터미널(들),또 다른 화면에는 웹 브라우저(들)뿐이다. 크롬OS는 개발자 모드로 shell을 사용할수 있으므로, 코딩하는게 크게 문제는 없다.</p>
<p><img src="https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-prn2/t1/1517671_10152197112378647_1643871268_n.jpg" alt="enter image description here"></p>
<p>Acer C720의 개발자 모드 사용법은 <a href="http://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices/acer-c720-chromebook">http://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices/acer-c720-chromebook</a> 참고.</p>
<p>Ctrl + alt + t 을 누르면 crosh가 뜬다. 하지만 크롬탭으로 실행되기때문에 단축키 충돌등이 발생한다.</p>
<p><a href="https://chrome.google.com/webstore/detail/crosh-window/nhbmpbdladcchdhkemlojfjdknjadhmh">crosh window</a> 을 설치하면 window으로 따로 띠우기 때문에 사용하기 좀 더 편하다. (문제는 터미널을 탭으로 더 띠울수 없다)</p>
<p>그리고 Ubuntu/Debian을 사용하기 위해서 <a href="https://github.com/dnschneid/crouton">crouton</a>을 설치했다.
(cli-extra으로 CLI만 사용하도록 설치)</p>
<p>거의 회사에서 쓰는 ubuntu와 비슷하다. 단 다음과 같은 사용시에 단점들이 있긴 하지만.</p>
<ul>
<li>crosh window에서 한글이 되지 않는다.</li>
<li>docker가 설치되지 않는다. chromeos의 linux kernel이 docker가 필요하게 구성되어 있지 않다.</li>
</ul>
<p>싸고 터미널과 웹만 있으면 코딩이 가능한 사람들에게는 추천할 만하다고 생각한다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>C&#43;&#43; For C Programmers 코세라 코스</title>
      <link>https://blog.anarcher.dev/post/2013/11-23-cpp-course/</link>
      <pubDate>Sat, 23 Nov 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/11-23-cpp-course/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.coursera.org/course/cplusplus4c&#34;&gt;C++ for C Programmers&lt;/a&gt; 코세라 수업이 끝났다.&lt;/p&gt;
&lt;img src=&#34;https://blog.anarcher.dev/img/post/cpp4c-soa.jpg&#34; /&gt;
&lt;p&gt;코세라 코스는 끝나고 인증서를 주는데 (물론 코세라 강의를 잘 들었다 정도의 의미이다.)
저번에 &lt;a href=&#34;https://www.coursera.org/course/progfun&#34;&gt;Function programming In Scala&lt;/a&gt; 다음으로 힘들었다.&lt;/p&gt;
&lt;p&gt;강의 자체는 C++0x까지 있어서 C++ 언어를 한번 정리하는 점으로는 좋았다.
하지만 숙제는 C/C++ 지식만 가지고는 풀수가 없었는데. 특히 알고리즘 기반의 숙제는 C++ 학습만
생각하고 시작했던 나에게는 조금 당혹스러워 했었다고 해야 하나.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://www.coursera.org/course/cplusplus4c">C++ for C Programmers</a> 코세라 수업이 끝났다.</p>
<img src="/img/post/cpp4c-soa.jpg" />
<p>코세라 코스는 끝나고 인증서를 주는데 (물론 코세라 강의를 잘 들었다 정도의 의미이다.)
저번에 <a href="https://www.coursera.org/course/progfun">Function programming In Scala</a> 다음으로 힘들었다.</p>
<p>강의 자체는 C++0x까지 있어서 C++ 언어를 한번 정리하는 점으로는 좋았다.
하지만 숙제는 C/C++ 지식만 가지고는 풀수가 없었는데. 특히 알고리즘 기반의 숙제는 C++ 학습만
생각하고 시작했던 나에게는 조금 당혹스러워 했었다고 해야 하나.</p>
<p>나름 잘 모르는 알고리즘도 알게 되고 나쁘지는 않았지만. 거의 한달간 주말은 없었다고 해도 무방했다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Chef 사용기</title>
      <link>https://blog.anarcher.dev/post/2013/09-25-1-week-chef/</link>
      <pubDate>Wed, 25 Sep 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/09-25-1-week-chef/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.
&amp;ndash; Phil Karlton&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Chef을 써보면서, 요리에 관련된 메타포를 사용하여 Chef 구성요소들의 이름들을 잘 지었다는 생각이 든다.
Chef을 구성하는 요소에 대한 설명을 간단히 몇개 적어 보자면:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chef    : 요리사,Server Configuration Project&lt;/li&gt;
&lt;li&gt;Recipe  : 요리법,어떤 작업을 할지 서술하는 목록&lt;/li&gt;
&lt;li&gt;Cookbook: 요리책,Recipe의 모음집.&lt;/li&gt;
&lt;li&gt;Knife   : 칼 요리도구,Chef의 CLI 도구&lt;/li&gt;
&lt;li&gt;Node    : 구성 작업할 서버&lt;/li&gt;
&lt;li&gt;Workstation : 작업장, Knife등의 도구를 통해 Chef에 작업을 하는 머신.&lt;/li&gt;
&lt;li&gt;Data bag : Chef Server에 JSON기반으로 저장되는 데이터&lt;/li&gt;
&lt;li&gt;Run list : Node에 작업할 목록(Cookbook의 Recipe나 다른 Role을 포함할수 있다)&lt;/li&gt;
&lt;li&gt;Attribute : 노드의 속성. Node와 Cookbook,Role,Environment에서 정의될수 있고,순서규칙에 따라 overide가 된다.&lt;/li&gt;
&lt;li&gt;Role : Run list와 Attribute을 가지는 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;물론 모든 단어가 요리에 관련된 단어는 아니다. 좀더 명확하게 설명할수 있는 요소는 굳이 사용하지 않은 듯 하다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p>There are only two hard things in Computer Science: cache invalidation and naming things.
&ndash; Phil Karlton</p></blockquote>
<p>Chef을 써보면서, 요리에 관련된 메타포를 사용하여 Chef 구성요소들의 이름들을 잘 지었다는 생각이 든다.
Chef을 구성하는 요소에 대한 설명을 간단히 몇개 적어 보자면:</p>
<ul>
<li>Chef    : 요리사,Server Configuration Project</li>
<li>Recipe  : 요리법,어떤 작업을 할지 서술하는 목록</li>
<li>Cookbook: 요리책,Recipe의 모음집.</li>
<li>Knife   : 칼 요리도구,Chef의 CLI 도구</li>
<li>Node    : 구성 작업할 서버</li>
<li>Workstation : 작업장, Knife등의 도구를 통해 Chef에 작업을 하는 머신.</li>
<li>Data bag : Chef Server에 JSON기반으로 저장되는 데이터</li>
<li>Run list : Node에 작업할 목록(Cookbook의 Recipe나 다른 Role을 포함할수 있다)</li>
<li>Attribute : 노드의 속성. Node와 Cookbook,Role,Environment에서 정의될수 있고,순서규칙에 따라 overide가 된다.</li>
<li>Role : Run list와 Attribute을 가지는 설정</li>
</ul>
<p>물론 모든 단어가 요리에 관련된 단어는 아니다. 좀더 명확하게 설명할수 있는 요소는 굳이 사용하지 않은 듯 하다.</p>
<p>좋았던 점은 Data bag과 Search 부분이다. 구성에 대한 정보를 Data bag의 Item으로 등록해두고 Recipe에서 사용하는 방식은 기능과 정보를 나누어서 관리 할수 있어서 데이터에 따른 recipe 사용이 좀더 편해진다.</p>
<p>특히 Chef REST API을 가지고 서버 구성하는 애플리케이션을 만들때, 따로 DB을 구성하지 않고 Chef의 Data bag을 사용할 수 있다 (트랜잭션이 크게 중요하지 않다는 판단하에).</p>
<p>구성이 끝나면,Chef의 Node에 추가되는데. Node의 정보(cpus,mem&hellip;)등도 함께 등록되기 때문에 현재 가용중인 서버들의 정보를 얻기에 쉽다.</p>
<p>이 부분에서 좀 아쉬운 부분은 구성 작업이 성공했는지 실패했는지에 대한 정보가 Node에 없어서 관련 Recipe을 만들어 줄 필요가 있다.</p>
<p>그리고 Chef 문서에도 있는 데, Databag이나 Cookbook등을 SCM(버젼관리) 저장소를 쓰는 것을 추천하는데. Chef server에 git이나 hg등의 scm 기능이 추가되어도 괜찮지 않을까 생각이 든다.</p>
<p>또 다른 아쉬운 점은 Chef은 기본적으로 하나의 노드에 대한 작업에 대한 부분만 고려되어 있는 듯 한 느낌이다. 즉 여러 노드를 병렬/순차적으로 작업해야 할때에 대한 기능이 직접적인 지원이 없다.
(예를 들어 AWS의 Cloudformation 같은 기능을 말한다)</p>
<p>자체적으로 데이터 스토어가 있다는 점, 중앙 관리가 가능하다는 점에서는 Chef 사용에 있어 좋은 점이라고 생각된다.</p>
<p>Chef을 사용하지 않고 하려면 어떤 도구들을 사용하면 될까?
개인적으로는 Ansible와 Zookeeper을 가지고 비슷하게 구성해볼수 있지 않을까 생각된다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>기분전환용 프로젝트 Soundcloud control button</title>
      <link>https://blog.anarcher.dev/post/2013/09-01-project-soundcloudbutton/</link>
      <pubDate>Sun, 01 Sep 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/09-01-project-soundcloudbutton/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://twitter.com/outsideris&#34;&gt;@Outsider&lt;/a&gt;님의 &lt;a href=&#34;http://blog.outsider.ne.kr/973&#34;&gt;기분전환용 프로젝트 Gittip-links&lt;/a&gt;에 영감을 받아서 나도 한번 만들어 봤다.&lt;/p&gt;
&lt;h1 id=&#34;동기&#34;&gt;동기&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://soundcloud.com/&#34;&gt;Soundcloud&lt;/a&gt;에서 이런 저런 Podcast을 자주 듣는 편이다. 주로 크롬 웹 브라우저에서 듣는데. 보통 탭이 한두개가 아닌지라 Soundcloud에서 듣다가 음악이나 방송을 끄거나 하려면 종종 열려 있는 탭에서 찾아야 하는 점이 불편했다. 그래서 크롬 익스텐션으로 만들어서 쉽게 (혹은 빠르게) 재생/중지를 할수 있으면 좋지 않을까 싶었다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://twitter.com/outsideris">@Outsider</a>님의 <a href="http://blog.outsider.ne.kr/973">기분전환용 프로젝트 Gittip-links</a>에 영감을 받아서 나도 한번 만들어 봤다.</p>
<h1 id="동기">동기</h1>
<p><a href="https://soundcloud.com/">Soundcloud</a>에서 이런 저런 Podcast을 자주 듣는 편이다. 주로 크롬 웹 브라우저에서 듣는데. 보통 탭이 한두개가 아닌지라 Soundcloud에서 듣다가 음악이나 방송을 끄거나 하려면 종종 열려 있는 탭에서 찾아야 하는 점이 불편했다. 그래서 크롬 익스텐션으로 만들어서 쉽게 (혹은 빠르게) 재생/중지를 할수 있으면 좋지 않을까 싶었다.</p>
<p>만들고 나서, <a href="https://www.google.co.kr/search?q=sound&#43;cloud&#43;button&#43;&amp;oq=sound&#43;cloud&#43;button&#43;&amp;aqs=chrome..69i57j69i60j0l2j69i60l2.5935j0&amp;sourceid=chrome&amp;ie=UTF-8#newwindow=1&amp;psj=1&amp;q=soundcloud&#43;button&#43;extension">soundcloud button extension</a> 으로 구글링해보면, opera용 add-on 이 있기는 하다. (사실 설명 부분은 살짝 베끼긴 했다. 영어 실력으로 부족으로.;ㅁ;)</p>
<h1 id="개발">개발</h1>
<p>사실 크롬 익스텐션을 만들어 본적이 없었기 때문에, 2시간-프로젝트(2HourProject)가 될거라고는 생각하지 않았다. 그래도 <a href="https://github.com/outsideris/gittip-links">https://github.com/outsideris/gittip-links</a> 코드도 좀 보고,구글 튜토리얼도 보면서 이것저것 HelloWorld 수준의 코드를 만들어 보면서 만들긴 했다. 대충 업로드와 이미지 작업 빼고 5시간 정도 걸린듯 하다.(카페에서 친구와 잡담도 하고 멍하니 있기도 해서 정확한 시간은 모르겠다.;)</p>
<p>하면서 아이콘 이미지 만드는 것 하나 잘 모른다는 걸 알았다. Soundcloud의 버튼을 쓰고 싶었지만,
배경을 투명하게 만드는 것도 하기 힘들어서 포기하고 <a href="http://findicons.com/icon/248309/play">http://findicons.com/icon/248309/play</a> 을 가져다가 썼다. (라이센스는 프리웨어,비상업)</p>
<p>이미지 툴도 없어서 GIMP을 맥에 설치할까 했지만, 웹에 있는 <a href="http://pixlr.com/editor/">http://pixlr.com/editor/</a> 을 알게 되어서 조금 써볼려고 해봤다. (결론은 실패.:-( )</p>
<p>크롬 익스텐션의 구조는 매우 간단해서 background page에 soundcloud page에 반응하는 content script가 dom을 읽어서 Message passing 하는 구조이다.</p>
<p>크롬 익스텐션이 의외로 어렵진 않았는데, 간단한 것을 만들어서 크게 내부 구조를 알 필요가 없긴 했다.</p>
<h1 id="에필로그">에필로그</h1>
<p>나 혼자 쓰게 될것 같은데. ㅎㅎ 우선 간단한 아이디어라도 구현해보니 나쁘지 않았다.
만들자 마자 올려서 어떤 버그가 있는 지도 안알라줌. (나도 모르지만 존재 여부는 당연히.. ;ㅁ;)</p>
<p>소스는 <a href="https://github.com/anarcher/SoundCloudControlButton">여기</a> 에 있고,익스텐션은 <a href="https://chrome.google.com/webstore/detail/soundcloud-control-button/ncmhcpmbfcnmnbhfpndnfmjgifcifamn">여기</a>에 있다.</p>
<p>ps)재미삼아 오마주한 프로젝트의 블로그 글을 따라했다. ㅎㅎㅎ</p>
]]></content:encoded>
    </item>
    <item>
      <title>Designing REST API</title>
      <link>https://blog.anarcher.dev/post/2013/08-17-designing-rest-api/</link>
      <pubDate>Sat, 17 Aug 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/08-17-designing-rest-api/</guid>
      <description>&lt;p&gt;REST API는 RPC(Remote Procedure Call) API와 다르게 기본적으로 절차적인 명령 호출의 목록으로 설계하는 것이 아니라고 생각된다.&lt;/p&gt;
&lt;p&gt;REST(Representational State Transfer) API는 선언적인 방법으로 리소스(Resource)의 표현되는 상태를 변화(GET,POST,PUT,PATCH,DELETE&amp;hellip;)시키는 인터페이스라고 할수 있다.&lt;/p&gt;
&lt;p&gt;그리고 이러한 리소스의 상태에 따라 시스템이 동작하는 구조라고 생각한다.(직접 시스템의 동작을 명령하는 인터페이스를 가진 것이 아닌.)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>REST API는 RPC(Remote Procedure Call) API와 다르게 기본적으로 절차적인 명령 호출의 목록으로 설계하는 것이 아니라고 생각된다.</p>
<p>REST(Representational State Transfer) API는 선언적인 방법으로 리소스(Resource)의 표현되는 상태를 변화(GET,POST,PUT,PATCH,DELETE&hellip;)시키는 인터페이스라고 할수 있다.</p>
<p>그리고 이러한 리소스의 상태에 따라 시스템이 동작하는 구조라고 생각한다.(직접 시스템의 동작을 명령하는 인터페이스를 가진 것이 아닌.)</p>
<p>REST API을 설계할때, RPC API 설계개념을 가져와 작성하게 되면 HTTP Methods(GET,POST,PUT&hellip;)으로 동작으로 명령을 정의하게 되어서 표현제약이 발생하고,결국 리소스을 가져다가 특정 동작을 정의하게 된다.</p>
<p>책 &ldquo;일관성 있는 웹 서비스 인터페이스 설계를 위한 REST API 디자인 규칙&quot;에서는 리소스 프로토타입에서 컨트롤러라는 이름으로 이러한 절차적인 호출을 위한 프로토타입이 있기는 하다.</p>
<p>하지만 기본적으로 리소스의 상태를 변화시키는 방법으로는 만들수 없는 경우에 사용되는 프로토타입이라고 생각된다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Bidirectional RPC in go</title>
      <link>https://blog.anarcher.dev/post/2013/07-28-bidi-rpc/</link>
      <pubDate>Sat, 27 Jul 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/07-28-bidi-rpc/</guid>
      <description>&lt;p&gt;예를 들어, Master Server와 Master의 지령을 받는 Worker Daemon가 있다고 하자.&lt;/p&gt;
&lt;p&gt;Master가 특정 Task를 Worker에 요청을 하려고 하는데, 여러가지 이유로 Master가 Worker에 접속을 하는 구조가 아닌, Worker가 실행할때 Master에 접속 할수만 있다고 하자.&lt;/p&gt;
&lt;p&gt;(특히 내부 IP만 가진 Worker라면 Master가 Worker에 접속을 할수가 없다.)&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>예를 들어, Master Server와 Master의 지령을 받는 Worker Daemon가 있다고 하자.</p>
<p>Master가 특정 Task를 Worker에 요청을 하려고 하는데, 여러가지 이유로 Master가 Worker에 접속을 하는 구조가 아닌, Worker가 실행할때 Master에 접속 할수만 있다고 하자.</p>
<p>(특히 내부 IP만 가진 Worker라면 Master가 Worker에 접속을 할수가 없다.)</p>
<p>ThriftRPC나 MsgpackRPC의 구조를 보면, Client/Server 구조로 Client가 Server의 Procedure을 원격 실행하는 방법만 지원한다.</p>
<p>(Thrift에서 양방향 RPC을 쓰고 싶다면 <a href="http://joelpm.com/2009/04/03/thrift-bidirectional-async-rpc.html">http://joelpm.com/2009/04/03/thrift-bidirectional-async-rpc.html</a> 을 참고,써보지는 않았다. 자바만 지원.)</p>
<p>밑으로 내려가서 보면, TCP은 기본적으로 Full-duplex 데이터 전달이 가능하다.
TCP, 또는 웹이라면 WebSocket 기반으로 Bidirectional RPC을 만들면 가능하다고 할수 있는데.</p>
<p>RPC을 만들기 보다는 기존의 RPC 라이브러리를 사용하고 싶어서, 다음과 같이 구성을 해보려고 한다.</p>
<ul>
<li>MasterServer는 두개의 정의된 Port를 Listen 한다.</li>
<li>한 Port는 Client가 Server에 RPC하는 Port이고,</li>
<li>나머지 한 Port은 Server가 Client에 RPC하는 Port이다.</li>
</ul>
<p>Connection이 두개 생기기는 하지만, 기존의 RPC 라이브러리를 사용하여 양방향 RPC을 가능해진다.
golang의 <a href="http://golang.org/pkg/net/rpc/">net/rpc</a> 을 가지고 간단히 Server에서 Client에 Remote Procedure Call을 해 볼수 있다.</p>
<pre><code data-language="go">package main

import (
    "net"
    "net/rpc"
    "log"
    "time"
    "fmt"
)

func requestToClient(conn net.Conn) {
    client := rpc.NewClient(conn)
    var out string

    for i := 0 ; i < 5 ; i ++  {
        log.Println("S: echo.echo")
        client.Call("Echo.Echo",fmt.Sprintf("%s:%d","hello client!",i),&out)
        log.Println("E: echo.echo",out)
        time.Sleep(100 * time.Millisecond)
    }
}

func main() {

    li,err := net.Listen("tcp",":1234")
    if err != nil {
        log.Fatal(err)
    }

    log.Println("Starting server")

    for {
        conn,_err := li.Accept()
        if _err != nil {
            log.Fatal(err)
        }

        log.Printf("Connected client: %v",conn.RemoteAddr())
        go requestToClient(conn)
    }
}
</code></pre>
<p>Client가 접속을 하면 Server은 접속한 Connection을 가지고  rpc client을 만들어서 요청을 한다.</p>
<pre><code data-language="go">package main
import (
    "net"
    "net/rpc"
    "log"
    "fmt"
)


func main() {

    echo := new(Echo)
    rpc.Register(echo)

    conn,err := net.Dial("tcp",":1234")
    if err != nil {
        log.Fatal(err)
    }

    go rpc.ServeConn(conn)

    var input string
    fmt.Scanln(&input)

}
</code></pre>
<p>Client은 Server에 접속한 후에 등록된 Procedure의 요청을 받기 위해 rpc.ServeConn을 사용한다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>10gen의 온라인 강의</title>
      <link>https://blog.anarcher.dev/post/2013/06-25-10gen-m102/</link>
      <pubDate>Sun, 23 Jun 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/06-25-10gen-m102/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://education.10gen.com&#34;&gt;10gen의 Mongodb 온라인 수업중 하나인 M102: MongoDB for DBAs&lt;/a&gt;을 들었다.&lt;/p&gt;
&lt;img src=&#34;https://blog.anarcher.dev/img/post/10gen-m102.jpg&#34; /&gt;
&lt;p&gt;개인적으로 MongoDB을 많이 좋아하지는 않지만(비슷한 것으로 &lt;a href=&#34;http://www.rethinkdb.com/&#34;&gt;RethinkDB&lt;/a&gt;가 더 맘에 든다.)
그래서 오히려 온라인 강의를 들어서 배우는게 어떨까 싶었다.&lt;/p&gt;
&lt;p&gt;10gen(MongoDB 제작사)은 커뮤니티를 만드는 작업을 굉장히 잘한다는 생각이 든다. 이런 온라인 코스도 코세라만큼 구성 자체를 잘 되어 있는 편.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://education.10gen.com">10gen의 Mongodb 온라인 수업중 하나인 M102: MongoDB for DBAs</a>을 들었다.</p>
<img src="/img/post/10gen-m102.jpg" />
<p>개인적으로 MongoDB을 많이 좋아하지는 않지만(비슷한 것으로 <a href="http://www.rethinkdb.com/">RethinkDB</a>가 더 맘에 든다.)
그래서 오히려 온라인 강의를 들어서 배우는게 어떨까 싶었다.</p>
<p>10gen(MongoDB 제작사)은 커뮤니티를 만드는 작업을 굉장히 잘한다는 생각이 든다. 이런 온라인 코스도 코세라만큼 구성 자체를 잘 되어 있는 편.</p>
]]></content:encoded>
    </item>
    <item>
      <title>DevFest W Seoul</title>
      <link>https://blog.anarcher.dev/post/2013/03-02-devfest-w-seoul/</link>
      <pubDate>Sat, 02 Mar 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/03-02-devfest-w-seoul/</guid>
      <description>&lt;p&gt;오랜만에 데브 페스트에 놀려 갔다.
&lt;a href=&#34;https://sites.google.com/site/2013devfestwkorea/home/aboutspeaker&#34;&gt;https://sites.google.com/site/2013devfestwkorea/home/aboutspeaker&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;구글인앱빌링-사용-모듈-구현사례&#34;&gt;구글인앱빌링 사용 모듈 구현사례&lt;/h2&gt;
&lt;p&gt;안드로이드 프로그래밍을 해본 경험이 없어서,잘 알지 못하는 분야이다.
구글의 인앱빌딩 지원을 버젼별로 상세히 설명되어있고,적어도 (나처럼 무경험자에게는)
어떻게 동작하는지 알수 있는 자리이었다.&lt;/p&gt;
&lt;p&gt;나중에 안드로이드 프로그래밍을 한다면,그때 다시 한번 찾아 볼듯 하다.&lt;/p&gt;
&lt;h2 id=&#34;go-lang-for-java-programmer&#34;&gt;Go Lang for Java Programmer&lt;/h2&gt;
&lt;p&gt;GoLang에 대한 기본적인 문법과 개념을 설명했다.
발표에 대한 연습을 많이 했다는 걸 느낄수 있었다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>오랜만에 데브 페스트에 놀려 갔다.
<a href="https://sites.google.com/site/2013devfestwkorea/home/aboutspeaker">https://sites.google.com/site/2013devfestwkorea/home/aboutspeaker</a></p>
<h2 id="구글인앱빌링-사용-모듈-구현사례">구글인앱빌링 사용 모듈 구현사례</h2>
<p>안드로이드 프로그래밍을 해본 경험이 없어서,잘 알지 못하는 분야이다.
구글의 인앱빌딩 지원을 버젼별로 상세히 설명되어있고,적어도 (나처럼 무경험자에게는)
어떻게 동작하는지 알수 있는 자리이었다.</p>
<p>나중에 안드로이드 프로그래밍을 한다면,그때 다시 한번 찾아 볼듯 하다.</p>
<h2 id="go-lang-for-java-programmer">Go Lang for Java Programmer</h2>
<p>GoLang에 대한 기본적인 문법과 개념을 설명했다.
발표에 대한 연습을 많이 했다는 걸 느낄수 있었다.</p>
<p>사실 나는 Go에 관심이 있어서 DevFest에 참가한 것이라고 할수 있는데. 기본적인 GoLang에 대한 차분한 설명을 잘 들을수 있었다.</p>
<h2 id="chrome-ui-frameworks">Chrome UI Frameworks</h2>
<p>크롬OS의 Arua UI에 대한 기본적인 설명을 하는 세션이었다.
Arua UI는 원도우 UI 시스템인데, 사실 난 크롬OS에서 크게 감흥이 없어서 그런지 UI을 구경하는 자리이었던것 같다.</p>
<p>기억이 남는 부분은 GtkWindow을 쓰지않고 구글은 독자적으로 Arua UI을 만들었다는 점.
기능한 어떤 이점이 있는지 모르겠다.</p>
<h2 id="how-to-live-like-goer">How to live like goer</h2>
<p>가장 재미있게 들은 발표이다.
Python에서 Go으로 넘어가면서의 기록이라고도 할수 있는데. 무언가 정확한 정보를 전달하는 것보다
사변적으로 이런 저런 다른 이의 생각과 경험을 알수 있어서 그런지 가장 즐거웠다.</p>
<h2 id="anguarjs">AnguarJS</h2>
<p>사실 Web Frontend에서 ServerSideRendering와 ClientSideRendering에 대해 갑을논박이 많은 듯 하다.
이부분은 사실 IRC(오징어의 #codeport에 놀려 오시면 종종 이런 이야기하는 무리?를 발견할수 있다.)에서 사람들과 이야기 하곤 했는데.
ClientSideRendering에서 Backbone.js보다 더 요즘 인기를 얻고 있는 프레임워크이라서 관심이 있었다.</p>
<p>Backbone.js보다 좀더 일체화된 구성을 가지고 있는데. 많은 부분이 구성이 되어 있어서 Backbone.js보다 좀더 쉽게 시작할수 있는 것 같다.</p>
<p>요즘 Backbone.js에서는 view dispose에 대한 이슈로 패치가 추가되었는데. AnguarJS에서는 어떤식으로 객체의 확득과 소멸을 하는지 궁금해졌다.</p>
<p>특히 One page application에서는 JS의 메모리 관리가 큰 이슈가 된다고 생각한다.</p>
<h2 id="concurrency-is-not-parallelism">Concurrency is not parallelism</h2>
<p>RobPike의 &ldquo;Concurrency is not parallelism&quot;을 GoLangUserGroup에서 다시 발표한 것이다.
CSP의 개념을 가지고 만든 동시성을 지원하는 Golang의 goroutine으로 병렬성을 어떻게 얻는지에 대한 이야기이다.</p>
<p>Concurrency은 프로그램의 특성이고,Parallel은 기계의 성질이다. 어떤 프로그램이 동시에 여러 루틴이 돌아간다면 Concurrency한 것이고,이 프로그램이 정말 동시에 동작할지는 사실 머신에 따라 다르다.
싱글 코어에서도 Concurrent하게 돌겠지만(시분할), 정말 병렬적으로 돌려면, 멀티코어상에서 가능하다.</p>
<p>GoLang의 동시성 지원은 멀티코어 시대의 위기?를 해결하고자 이슈를 얻고 있는 함수형 프로그래밍(물론 이것 하나때문에 요즘 관심을 받는 것은 아니지만)에 대한 생각을 다시 하게 만들었다.</p>
<p>어떤 goroutine들은  Concurrent을 한 Thread에서만 획득하고 싶다거나(ThreadContention을 피하고 싶을 경우라든가) 하는 구성을 어떻게 하는지 궁금해졌다.
예를 들어,goroutine으로 PythonGenerator을 구성한다면 말이다.</p>
<h2 id="오랜만의-컨퍼런스">오랜만의 컨퍼런스</h2>
<p>사실 3일연휴이라서 여유가 있기에 올수 있었다. 나도 컨퍼런스에 대한 맘이 예전같지 않다.(응?;)
나름 지인들도 보고 공짜 점심도 먹을 수 있어서..;ㅁ; 즐거운 하루이었던것 같다.
아래는 발표자료 링크이다.</p>
<p><a href="https://docs.google.com/a/enswer.net/folder/d/0B82z67M0_dLHWXdfNEtMQ2hYSXM/edit?usp=sharing">https://docs.google.com/a/enswer.net/folder/d/0B82z67M0_dLHWXdfNEtMQ2hYSXM/edit?usp=sharing</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>REST API 디자인 룰 북</title>
      <link>https://blog.anarcher.dev/post/2013/02-10-restapi/</link>
      <pubDate>Sun, 10 Feb 2013 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2013/02-10-restapi/</guid>
      <description>&lt;p&gt;REST API을 만드는 일이 많아졌다.
REST API가 이미 널리 알려진 개념이지만,RESTful하다고 할수 있는 API은 어느정도는 주관적인 요소가 개입되는 것 같다.&lt;/p&gt;
&lt;p&gt;이번에 설계를 하면서, Twitter나 Facebook의 API을 참고하긴 했지만, 각각의 스타일의 차이를 알수는 있어도 좋은 디자인 규칙에 대한 정보를 얻기가 힘들었다.&lt;/p&gt;
&lt;p&gt;특히 리소스 모델링 부분이 어려운데, &lt;a href=&#34;http://shop.oreilly.com/product/0636920021575.do&#34;&gt;REST API Design Rulebook&lt;/a&gt;을 참고하여 구성하고 있다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>REST API을 만드는 일이 많아졌다.
REST API가 이미 널리 알려진 개념이지만,RESTful하다고 할수 있는 API은 어느정도는 주관적인 요소가 개입되는 것 같다.</p>
<p>이번에 설계를 하면서, Twitter나 Facebook의 API을 참고하긴 했지만, 각각의 스타일의 차이를 알수는 있어도 좋은 디자인 규칙에 대한 정보를 얻기가 힘들었다.</p>
<p>특히 리소스 모델링 부분이 어려운데, <a href="http://shop.oreilly.com/product/0636920021575.do">REST API Design Rulebook</a>을 참고하여 구성하고 있다.</p>
<h2 id="resource의-프로토타입을-제시">Resource의 프로토타입을 제시</h2>
<p><a href="http://shop.oreilly.com/product/0636920021575.do">REST API Design Rulebook</a>에서는 리소스의 원형을 다음과 같이 제시한다.</p>
<ul>
<li>도큐먼트</li>
<li>컬렉션</li>
<li>스토어</li>
<li>컨트롤러</li>
</ul>
<p>이중에서 가장 흥미로운 리소스 원형은 컨트롤러 리소스와 스토어 리소스이다.
컨트롤러 리소스는 사실 HTTP Method으로는 표현하기 힘든 행동을 리소스로 표현하기 위해 존재한다.</p>
<pre><code>POST /alerts/23456/resend 
</code></pre>
<p>스토어 리소스는 기본적으로 클라이언트가 관리하는 리소스이다. (다른 3개의 리소스는 서버-사이드 리소스이다)
그리고 새로운 리소스를 만들지 못한다.</p>
<p>예를 들어, 서버에서 관리하는 리소스인 컬렉션 리소스에 어떤 도큐먼트 리소스를 포함(저장)하는 행동을 클라이언트가 스토어 리소스로 할수 있다. (이는 기존에 존재하는 리소스의 관계를 만드는(저장하는) 행동이기 때문에 새로운 리소스를 만든다고 할수 없는 것 같다)</p>
<p>개인적인 짧은 생각으로는 스토어 리소스라는 이름보다는 릴레이션 리소스 같은 이름이 좀더 명확한것이 아닌가 싶다.</p>
<p>이책의 저자는 이런 리소스 디자인을 가지고 <a href="http://www.wrml.org">Web Resource Modeling Language</a>이라는 프로젝트를 하고 있지만,큰 호응이 있는 것 같지는 않다.</p>
<p>관례적으로 (예상되겠지만) 도규먼트는 단수 명사, 콜렉션은 복수 명사,스토어는 복수 명사,컨트롤러는 동사를 사용한다.  <a href="http://www.wrml.org/modelingLanguage">http://www.wrml.org/modelingLanguage</a></p>
<p>이런 리소스의 원형(혹은 규칙)을 가지고 API을 만든다면 좀더 일관성이 있는 REST API을 만들기 좋지 않나 싶다.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Functional programming in scala 코세라 코스</title>
      <link>https://blog.anarcher.dev/post/2012/12-20-functional-programming-scala/</link>
      <pubDate>Thu, 20 Dec 2012 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2012/12-20-functional-programming-scala/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://www.coursera.org/course/progfun&#34;&gt;Functional programming In Scala&lt;/a&gt; 코세라 수업이 끝났다.&lt;/p&gt;
&lt;img src=&#34;https://blog.anarcher.dev/img/post/fpis-2012.jpg&#34; /&gt;
&lt;p&gt;강의도 좋지만, 숙제가 TDD기반으로 작성하여 작성한 코드를 코세라에 업로드하면 채점용 TestCase가 돌아서 채점이 된다. 이런 부분들의 준비가 굉장히 잘되어 있다.&lt;/p&gt;
&lt;p&gt;정말 어려웠던 수업이기도 했다. =_=&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://www.coursera.org/course/progfun">Functional programming In Scala</a> 코세라 수업이 끝났다.</p>
<img src="/img/post/fpis-2012.jpg" />
<p>강의도 좋지만, 숙제가 TDD기반으로 작성하여 작성한 코드를 코세라에 업로드하면 채점용 TestCase가 돌아서 채점이 된다. 이런 부분들의 준비가 굉장히 잘되어 있다.</p>
<p>정말 어려웠던 수업이기도 했다. =_=</p>
]]></content:encoded>
    </item>
    <item>
      <title>Disco 사용기</title>
      <link>https://blog.anarcher.dev/post/2011/08-03-disco/</link>
      <pubDate>Wed, 03 Aug 2011 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/post/2011/08-03-disco/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;http://discoproject.com/&#34;&gt;Disco&lt;/a&gt;을 잘 모르지만, 이번에 통계관련 계산에 한번 써봤다.&lt;/p&gt;
&lt;h2 id=&#34;mapreduce&#34;&gt;map/reduce&lt;/h2&gt;
&lt;p&gt;map/reduce는 map의 결과가 하나의 reduce에서 같은 key으로 모이는 것 보장한다.로직에 따라 다르겠지만.  전체 갯수을 얻는 것이 아니라면 reduce을 늘리는 것이 성능에 좋다. (당연한 이야기이지만)&lt;/p&gt;
&lt;h2 id=&#34;combiner&#34;&gt;combiner&lt;/h2&gt;
&lt;p&gt;Disco 문서에서는 보기 힘든데, Hadoop처럼 combiner을 만들 수 있다. combiner은 일종의 accumulator인데. 각 map마다 map의 결과를 받아서 reduce에 넘기기전에 buffer을 가진 function(combiner)을 만들 수 있는데. 대부분의 경우 combiner을 만드는 것이 속도나 메모리 사용에 좋을 것 같다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://discoproject.com/">Disco</a>을 잘 모르지만, 이번에 통계관련 계산에 한번 써봤다.</p>
<h2 id="mapreduce">map/reduce</h2>
<p>map/reduce는 map의 결과가 하나의 reduce에서 같은 key으로 모이는 것 보장한다.로직에 따라 다르겠지만.  전체 갯수을 얻는 것이 아니라면 reduce을 늘리는 것이 성능에 좋다. (당연한 이야기이지만)</p>
<h2 id="combiner">combiner</h2>
<p>Disco 문서에서는 보기 힘든데, Hadoop처럼 combiner을 만들 수 있다. combiner은 일종의 accumulator인데. 각 map마다 map의 결과를 받아서 reduce에 넘기기전에 buffer을 가진 function(combiner)을 만들 수 있는데. 대부분의 경우 combiner을 만드는 것이 속도나 메모리 사용에 좋을 것 같다.</p>
<h2 id="ddfs-chunk-size-와-map">ddfs chunk size 와 map</h2>
<p>ddfs에 데이터를 넣을때, 기본적으로 blob size은 64M이다. 문제는 mapper은 blob마다 할당되는데. 데이터가 좀더 넓게 펴져 있다면, 좀 더 많은 머신들이 map에 참여하게 된다.
ddfs command에서는 chunk size을 바꿀수 없고. ddfs chunk으로 넣은 데이터를 원하는 size으로 짤라주는 작업이 필요하다. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<h2 id="ddfs-chunk-읽기">ddfs chunk 읽기</h2>
<p>ddfs chunk도 일종의 mapreduce job으로 돌린다. ddfs xcat command처럼 chunk의 데이터를 읽으려면
disco_input_stream 으로 읽어야 한다.
ddfs command도 python code이니. ddfs command code을 참고했다.</p>
<h2 id="disco-vs-hadoop">Disco vs Hadoop</h2>
<p>대부분의 경우 단일 머신에서 계산을 비교하면 그냥 일반적인 계산 코드가 빠르다. 하지만 확장성이나 데이터를 분산해서 두고 규모가 커지더라도 대응할수 있게 만들려면 M/R이 나쁘지 않은 듯 하다.</p>
<p>내가 하는 Jobs들은 대용량의 데이터라기 보다는 많은 Jobs이 참여하는 구조이라서 (더군다나 계층적인 구조.. OTL) job들을 chaining해서 이전 reduce의 output이 다음 map의 input이 되는 패턴이 계층적으로 되어지니까 코드가 귀찮아 진다. (핑계 없는 무덤을 없더라는 속담을 생각하며. -_-)</p>
<p><a href="http://engineering.twitter.com/2011/08/storm-is-coming-more-details-and-plans.html">Storm</a>이나 <a href="https://github.com/mesos/spark">Spark</a>에서는 좀더 이런 구조에 적절할지 궁금하다.
그나저나 Storm은 이번달에 나오겠군.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Hadoop은 어떻게 작동하는지 잘 모르겠다. map의 partition을 줄수 있을 것 같은데. 처음에 당황했던 부분이다.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded>
    </item>
    <item>
      <title>About</title>
      <link>https://blog.anarcher.dev/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>ted@daangn.com (Anarcher)</author>
      <guid>https://blog.anarcher.dev/about/</guid>
      <description>&lt;p&gt;You can find out more about me across services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/anarcher&#34;&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://bsky.app/profile/anarcher.dev&#34;&gt;Bluesky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://twitter.com/anarcher&#34;&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<p>You can find out more about me across services:</p>
<ul>
<li><a href="https://github.com/anarcher">Github</a></li>
<li><a href="https://bsky.app/profile/anarcher.dev">Bluesky</a></li>
<li><a href="https://twitter.com/anarcher">Twitter</a></li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
