<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohammad Reza Karimi</title>
    <description>The latest articles on DEV Community by Mohammad Reza Karimi (@arshamalh).</description>
    <link>https://dev.to/arshamalh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F880474%2F6237dff1-1e1f-48c5-9e91-c666024d78ea.jpeg</url>
      <title>DEV Community: Mohammad Reza Karimi</title>
      <link>https://dev.to/arshamalh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arshamalh"/>
    <language>en</language>
    <item>
      <title>[TechStory]: How to add distributed tracing using Jaeger and OpenTelemetry into a Golang application</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Wed, 13 Dec 2023 08:39:43 +0000</pubDate>
      <link>https://dev.to/arshamalh/techstory-how-to-add-distributed-tracing-using-jaeger-and-opentelemetry-into-a-golang-application-1p37</link>
      <guid>https://dev.to/arshamalh/techstory-how-to-add-distributed-tracing-using-jaeger-and-opentelemetry-into-a-golang-application-1p37</guid>
      <description>&lt;p&gt;I recently had a tough time adding distributed tracing to our services using OpenTelemetry, Although that sounds not to be hard, lots of deprecated packages, changed solutions, no up-to-date documents, etc. led me to write this article &lt;strong&gt;for other engineers not to fall into the same hole&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I will start with a summary of the Tracing definition, then we will go through the right solution and mention holes along the way, it's my own experience (TechStory) and not a tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Tracing
&lt;/h2&gt;

&lt;p&gt;Tracing is the process of capturing and recording information about the execution of software, traces come along with metrics and logs and they help us to have a better #observablity over our services.&lt;/p&gt;

&lt;p&gt;Traces tell us what happened when, where, and took how long.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is distributed tracing
&lt;/h2&gt;

&lt;p&gt;In the microservices world, it's hard to see the request flow and integration between services, distributed tracing is a set of techniques that help us track user flow across multiple distributed services.&lt;/p&gt;

&lt;h2&gt;
  
  
  What tools can we use
&lt;/h2&gt;

&lt;p&gt;Tracing and Distributed Tracing come with a bunch of dependencies (they may not be a good choice for small code bases with a few users)&lt;/p&gt;

&lt;p&gt;The way of doing it and the number of dependencies also varies based on the tools you use and the architecture and design you follow, there might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent (a network daemon that listens for spans sent over UDP)&lt;/li&gt;
&lt;li&gt;Collector (receives traces from the SDKs or Jaeger agents, runs them through a processing pipeline for validation and clean-up/enrichment, and stores them in a storage backend)&lt;/li&gt;
&lt;li&gt;Trace DB (for example, Elasticsearch)&lt;/li&gt;
&lt;li&gt;SDK and Libraries (OpenTracing, OpenTelemetry, agent-specific libraries, etc).&lt;/li&gt;
&lt;li&gt;UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But we don't go through all of them in this article, we use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenTelemetry&lt;/li&gt;
&lt;li&gt;Jaeger all-in-one docker image (or Maintained Jaeger on Cloud)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Setup
&lt;/h2&gt;

&lt;p&gt;To setup OpenTelemtry SDK (a bunch of codes and function calls), you need to inject (pass) a Provider (Jaeger) to it, &lt;br&gt;
To initialize the provider, you need to write a code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;tp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTracerProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c"&gt;// The sampler determines how many requests to trace&lt;/span&gt;

 &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSampler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceIDRatioBased&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SamplerParam&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="c"&gt;// Always be sure to batch in production.&lt;/span&gt;
  &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithBatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

  &lt;span class="c"&gt;// Record information about this application in a Resource.&lt;/span&gt;
  &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWithAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;semconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SchemaURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;semconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceNameKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Then if you run &lt;code&gt;go mod tidy&lt;/code&gt; you may face this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go.opentelemetry.io/otel/semconv: module go.opentelemetry.io/otel@latest found (v1.13.0), but does not contain package go.opentelemetry.io/otel/semconv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that case, I wrote a good explanation and solution for you &lt;a href="https://stackoverflow.com/a/77547868/12972198"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;TL;DR: Old Deprecated Jaeger versions caused this error, and they are more than one,&lt;br&gt;
There were Deprecated Jaegers for OpenTracing, but OpenTracing itself is also deprecated.&lt;/p&gt;

&lt;p&gt;If you want to use OpenTelemetry Jaeger libraries instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://pkg.go.dev/go.opentelemetry.io/otel/exporters/trace/jaeger
https://pkg.go.dev/go.opentelemetry.io/otel/exporters/jaeger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are also deprecated!&lt;/p&gt;




&lt;p&gt;So What should we do? 😰&lt;br&gt;
In fact, All Jaeger libraries are deprecated and you should use &lt;code&gt;OTLP&lt;/code&gt; instead nowadays (OTLP is not deprecated at the time of writing this article! but the world has gone wild! I don't guarantee tomorrow 😂)&lt;/p&gt;
&lt;h2&gt;
  
  
  So what is this OTLP thing?
&lt;/h2&gt;

&lt;p&gt;In simple terms, OTLP (OpenTelemetry Protocol) is a protocol designed to standardize the telemetry data transfers between different clients, it's here to help the community not get the headache of being involved with a vast range of different tools and have a common standard instead.&lt;/p&gt;

&lt;p&gt;For more information, I recommend you read &lt;a href="https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/design-goals.md"&gt;their design goals&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;In cases where you use a Jaeger all-in-one image (jaegertracing/all-in-one), you should be aware that this image includes an OpenTelemetry collector in versions &amp;gt;= 1.35 and you don't need to run a separate container (&lt;a href="https://github.com/open-telemetry/opentelemetry-go/tree/main/example/otel-collector"&gt;this official documentation&lt;/a&gt; confused me about it).&lt;/p&gt;

&lt;p&gt;You should also expose some ports and enable some variables, I wrote a &lt;a href="https://gist.github.com/arshamalh/11d8466b91e370181b54890433070ac7"&gt;docker-compose file here that shows them all&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But if you have mismatched versions, you may get these errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;traces export: failed to send to http://localhost:14268/api/traces: 400 Bad Request
traces export: failed to send to http://localhost:4318/api/traces: 404 Not Found
traces export: Post "http://localhost:4318/api/traces": read tcp [::1]:60409-&amp;gt;[::1]:4318: read: connection reset by peer
traces export: Post "http://localhost:4318/v1/traces": dial tcp [::1]:4318: connect: connection refused
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply say, you can run an all-in-one version &amp;gt;= 1.35, expose port 4318, and send your traces to &lt;code&gt;http://localhost:4318/v1/traces&lt;/code&gt; which is the default OTLP config. (Jaeger agent was on e.g. &lt;code&gt;:6831/api/traces&lt;/code&gt;, but you don't need that anymore)&lt;/p&gt;




&lt;p&gt;Most of these issues were on Localhost, we had a managed Jaeger for production on our private cloud, and I got a new error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;traces export: context deadline exceeded: retry-able request failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It happened because I was sending the traces to Jaeger Agent's address on production but I should've sent them to the collector, so if you faced the same error, double-check your address.&lt;/p&gt;

&lt;h2&gt;
  
  
  Propagation
&lt;/h2&gt;

&lt;p&gt;Another hard topic was &lt;code&gt;Propagation&lt;/code&gt;, what is it?&lt;br&gt;
propagated traces are the ones that keep their identity the same across multiple services and help us see the request flow through a distributed system, this is possible by attaching some trace-specific headers to your request, and it's applicable in different scenarios whether it's a simple HTTP request or Kafka event, etc.&lt;/p&gt;

&lt;p&gt;There are two important notes here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each service should support tracing and it should also be enabled (services that don't support tracing, will not be in the flow)&lt;/li&gt;
&lt;li&gt;OpenTelemetry support Propagation Generally, it means you are responsible for "what headers" and it just attaches them to the request for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In case of implementation, you should first setup the propagator like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;jaegerPropagator&lt;/span&gt; &lt;span class="s"&gt;"go.opentelemetry.io/contrib/propagators/jaeger"&lt;/span&gt;
  &lt;span class="s"&gt;"go.opentelemetry.io/otel"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetTextMapPropagator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jaegerPropagator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Jaeger&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can &lt;code&gt;Inject&lt;/code&gt; context to request headers when you are sending a request, and &lt;code&gt;Extract&lt;/code&gt; them on the receiver side, and when the service is both receiver and sender, it may implement both &lt;code&gt;Inject&lt;/code&gt; and &lt;code&gt;Extract&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Inject:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ctx is the context that included some trace data&lt;/span&gt;
&lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetTextMapPropagator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HeaderCarrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract (happening in middleware in this case):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetTextMapPropagator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HeaderCarrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"middleware"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"middleware"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We talked about different challenges I faced during the Tracing setup, but the challenges still apply to other scenarios (even other languages), #mismatched_version, #wrong_addresses, and #deprecated_pkgs, etc.&lt;br&gt;
I hope you enjoyed this article.&lt;/p&gt;

</description>
      <category>tracing</category>
      <category>jaeger</category>
      <category>opentelemetry</category>
      <category>go</category>
    </item>
    <item>
      <title>[TechStory]: Migrating services and databases from an OpenShift (or K8s) cluster to another</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Sat, 03 Jun 2023 14:39:47 +0000</pubDate>
      <link>https://dev.to/arshamalh/techstory-migrating-services-and-databases-from-an-openshift-or-k8s-cluster-to-another-3i1h</link>
      <guid>https://dev.to/arshamalh/techstory-migrating-services-and-databases-from-an-openshift-or-k8s-cluster-to-another-3i1h</guid>
      <description>&lt;p&gt;Welcome Friends to another TechStory!&lt;/p&gt;

&lt;p&gt;My first experience with OpenShift was with a task which was kind of a heavy task, I didn't know anything about &lt;a href="https://docs.openshift.com" rel="noopener noreferrer"&gt;OpenShift&lt;/a&gt; or K8s! but I was in charge of migrating resources from a cluster to one another! (twice!)&lt;/p&gt;

&lt;p&gt;But I learned a lot of things in the middle, so let's have a look at some of those.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before going deep dive, you may wonder what is OpenShift and why do I put its name beside K8s everytime, It's actually becuase Openshift is built on top of K8s and it's kind of the same (+few more features), so don't worry about the difference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  So, What's the problem?
&lt;/h2&gt;

&lt;p&gt;As I told you before, I had to move resources such as Applications (pods+services+routes), Databases (+their data) from an &lt;a href="https://www.okd.io" rel="noopener noreferrer"&gt;OKD3 cluster&lt;/a&gt; to an &lt;a href="https://www.okd.io" rel="noopener noreferrer"&gt;OKD4 cluster&lt;/a&gt; (different versions of OpenShift)&lt;/p&gt;

&lt;p&gt;The reason of this migration? I'm not sure! &lt;br&gt;
To be honest, this was already decided and it was on the board,&lt;br&gt;
Also in some companies, Kubernetes has two sides, cloud side and developer side, we (developers) don't lunch Kubernetes, instead, we lunch our services on it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where did I start?
&lt;/h2&gt;

&lt;p&gt;I asked two question on Stackoverflow because it was not clear for me what to do at the first place, and there were a lot of suggestions, which I just mention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kubeshop/monokle" rel="noopener noreferrer"&gt;monokle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://velero.io/docs/v1.10/migration-case" rel="noopener noreferrer"&gt;Velero&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;OpenShift Official Guide called &lt;a href="https://docs.openshift.com/container-platform/4.12/migration_toolkit_for_containers/about-mtc.html" rel="noopener noreferrer"&gt;Migration Toolkit for Containers (MTC)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.openshift.com/container-platform/4.12/migrating_from_ocp_3_to_4/about-migrating-from-3-to-4.html" rel="noopener noreferrer"&gt;Another Official Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: Unfortunately I can't provide a link to questions, although they were well received but a moderator deleted them 🤔&lt;/p&gt;

&lt;p&gt;I also found and provided my answer, I followed it and I think it taught me a lot of things and there is nothing wrong with it, but it was not good enough solution for this case.&lt;/p&gt;
&lt;h2&gt;
  
  
  Not good enough solution!
&lt;/h2&gt;

&lt;p&gt;For making resources in a K8s cluster you should be careful about their priority,&lt;/p&gt;

&lt;p&gt;First things to make are secrets and config maps, because they don't depend on anything but everything can depend on them!&lt;/p&gt;

&lt;p&gt;And last things are routes, guess why? because they depend on services but nothing depends on them!&lt;/p&gt;

&lt;p&gt;So the priority is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secrets and ConfigMaps&lt;/li&gt;
&lt;li&gt;StatefulSets &lt;/li&gt;
&lt;li&gt;Deployments&lt;/li&gt;
&lt;li&gt;Services&lt;/li&gt;
&lt;li&gt;Routes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may not need to move pods directly, because they are usually made and controlled by other resources such as &lt;br&gt;
Deployments or StatefulSets.&lt;/p&gt;
&lt;h3&gt;
  
  
  Steps to follow:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Login to the first cluster:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc login --token="your-token-for-first-server" --server="your-first-server"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Export your resources:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc get -o yaml cm &amp;gt; configmaps.yaml
oc get -o yaml secrets &amp;gt; secrets.yaml
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;There are also some default ConfigMaps and Secrets which you don't need to copy, you can erase them from generated yaml files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login to the second cluster:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc login --token="your-token-for-second-server" --server="your-second-server"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you forget this step, you may get an error that says &lt;code&gt;resource already exists&lt;/code&gt;, but be careful not to forget this step.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load resources to the second cluster
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc create -f configmaps.yaml
oc create -f secrets.yaml
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Better solutions
&lt;/h2&gt;

&lt;p&gt;There was a better solution, we can use &lt;a href="https://docs.openshift.com/container-platform/4.9/openshift_images/using-templates.html" rel="noopener noreferrer"&gt;Templates&lt;/a&gt; and process them for different clusters, environments or namespaces.&lt;/p&gt;

&lt;p&gt;Also, combining them with CI/CD pipelines, helps us to move our resources by just changing some variables!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://helm.sh" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; works even better! I personally prefer Helm over basic templating.&lt;/p&gt;

&lt;p&gt;I improved our CI/CD pipelines and Helmified (used Helm 😁) our applications for easier, clean and seamless deployments.&lt;/p&gt;
&lt;h2&gt;
  
  
  What about DB?
&lt;/h2&gt;

&lt;p&gt;DB is also another important &amp;amp; long discussion here, but not the database application itself, we can easily create that, but what should we do about the data? data is everything!&lt;/p&gt;

&lt;p&gt;In my case, they were two scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production&lt;/li&gt;
&lt;li&gt;Stage (testing environment - production with fake data)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Production, we had a managed Database controlled and owned by DBA team, we just had URL for Accessing it and that was enough.&lt;/p&gt;

&lt;p&gt;So in cases that your accessing data which is in an external database (out of cluster), you don't need any extra work.&lt;/p&gt;

&lt;p&gt;But in Stage, our data was stored in a PVC attached to a Pod controlled by a StatefulSet.&lt;/p&gt;

&lt;p&gt;Note: We had MySQL, you may have something else, but the fellow is almost the same.&lt;/p&gt;
&lt;h3&gt;
  
  
  Steps to follow:
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Step 1: Login and port-forward
&lt;/h4&gt;

&lt;p&gt;Login to the first Openshift cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc login --token=&amp;lt;YOUR-TOKEN&amp;gt; --server=&amp;lt;YOUR-SERVER&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List all pods and select your db pod (if replicated, choose master (0)) and copy it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make a port-forwarding to your local computer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oc port-forward &amp;lt;MYSQL-POD-NAME&amp;gt; &amp;lt;desired-local-port&amp;gt;:&amp;lt;mysql-on-server-port&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So your server database is now (like) your local database! and any change you want on server can be done on &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This method is the same for all databases and also applications.&lt;/p&gt;




&lt;h4&gt;
  
  
  Step 2: tools
&lt;/h4&gt;

&lt;p&gt;Install &lt;code&gt;mysql&lt;/code&gt; command line tools (if you have them installed, skip this step).&lt;br&gt;
Specifically, we need &lt;code&gt;mysqldump&lt;/code&gt; and &lt;code&gt;mysql&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;To do so, on macos run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install mysql-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I needed to add them to path (it usually happens automatically), run command below and add &lt;code&gt;/opt/homebrew/opt/mysql-client/bin&lt;/code&gt; to the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nano /etc/paths 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other editors such as vscode (type &lt;code&gt;code&lt;/code&gt; in terminal) can be used instead of nano.&lt;/p&gt;

&lt;p&gt;Read &lt;a href="https://stackoverflow.com/a/54787376/12972198" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://www.architectryan.com/2012/10/02/add-to-the-path-on-mac-os-x-mountain-lion/#.Uydjga1dXDg" rel="noopener noreferrer"&gt;here&lt;/a&gt; for more information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: take a dump
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysqldump --column-statistics=0 --no-create-info -P &amp;lt;local-port&amp;gt; -h 127.0.0.1 -u &amp;lt;YOUR-USERNAME&amp;gt; -p "YOUR-DATABASE-NAME" &amp;gt; file_name.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you'll be asked to enter the database password for .&lt;/p&gt;

&lt;p&gt;In my case, I previously ran migration scripts so I didn't want my dump to include &lt;code&gt;CREATE TABLE...&lt;/code&gt; queries, so I added &lt;code&gt;--no-create-info&lt;/code&gt; argument, but you may want to erase it.&lt;/p&gt;

&lt;p&gt;Also, I was facing with &lt;code&gt;Unknown table 'COLUMN_STATISTICS' in information_schema (1109)&lt;/code&gt; error, so I added &lt;code&gt;--column-statistics=0&lt;/code&gt; argument.&lt;br&gt;
For more information, read &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html#option_mysqldump_column-statistics" rel="noopener noreferrer"&gt;here&lt;/a&gt; and &lt;a href="https://serverfault.com/a/912677/959490" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;About the host IP, do not use &lt;code&gt;localhost&lt;/code&gt;, it probably connects by socket rather than by port.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 4: load the dump
&lt;/h2&gt;

&lt;p&gt;Now, login to the second cluster, make the StatefulSet, and port-forward its database as explained before,&lt;br&gt;
(you can run your migration scripts here on this local-like database and they will be done on the cluster as well)&lt;/p&gt;

&lt;p&gt;Then, load the dump with below command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql -P &amp;lt;local-port&amp;gt; -h 127.0.0.1 -u &amp;lt;YOUR-USERNAME&amp;gt; -p -f "YOUR-DATABASE-NAME" &amp;lt; file_name.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, I had some unimportant errors, I've passed &lt;code&gt;-f&lt;/code&gt; argument to skip them, but be careful when using this argument as it forces the database to follow your introduction defined on &lt;code&gt;file_name.sql&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;TechStories are my real job experiences, they might be confusing as they include a lot of information and links to other articles, that's my point! we (developers) don't work in the way people see in usual articles and tutorials, so I want to share my knowledge beside teaching a lot of different tips that get related in my task.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed! 🥳✌🏼&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>mlm</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Make your cool commands in terminal</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Thu, 25 May 2023 07:23:35 +0000</pubDate>
      <link>https://dev.to/arshamalh/make-your-cool-commands-in-terminal-93o</link>
      <guid>https://dev.to/arshamalh/make-your-cool-commands-in-terminal-93o</guid>
      <description>&lt;p&gt;Hi guys,&lt;br&gt;
I wanna teach you how to make cool things in your terminal and increase your productivity like a pro.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You don't need any docker, k8s, Openshift or Golang experience for this article, we just used them as examples but you'll get the point in other cases too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Open your shell config file (e.g. &lt;code&gt;~/.zshrc&lt;/code&gt; in Mac)&lt;br&gt;
Write aliases commands like this &lt;code&gt;alias mycmd="cmd long long long"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and functions like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mf&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; 
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And call it in terminal like this: &lt;code&gt;mf mydir myfile&lt;/code&gt; and it will make a directory named &lt;code&gt;mydir&lt;/code&gt; and file within it named &lt;code&gt;myfile&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The story behind this article
&lt;/h2&gt;

&lt;p&gt;As a developer, you may work with CLIs a lot, CLIs are made to be general and composable, but in some specific cases, you may want to compose them as you wish once forever!&lt;/p&gt;

&lt;p&gt;For example, I need some specific compositions of &lt;code&gt;oc&lt;/code&gt; command for everyday use.&lt;/p&gt;

&lt;p&gt;Also, I needed 2 different VPN connections using 2 different clients, they had long commands!&lt;/p&gt;

&lt;p&gt;Sometimes they are long, sometimes they are hard to remember, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define aliases
&lt;/h2&gt;

&lt;p&gt;There is an &lt;code&gt;alias&lt;/code&gt; command available on *nix systems (Linux, Unix, MacOS, etc)&lt;/p&gt;

&lt;p&gt;It's an alternative command which you can use to make your commands shorter.&lt;/p&gt;

&lt;p&gt;In my case, I wanted to connect to a VPN with openfortivpn client like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo openfortivpn vpn.host.domain:port -u myusername -p mypassword --trusted-cert averyveryveryverylonghash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And another VPN using openconnect client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo openconnect -u myusername -p mypassword vpn.host.domain:port
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to that, every company or personal project that I worked for, I used &lt;code&gt;docker-compose up --build -d&lt;/code&gt; command, what does it do? doesn't matter!&lt;/p&gt;

&lt;p&gt;For this article, we just know that these commands are the same most of the time and typing them out is cumbersome.&lt;/p&gt;

&lt;p&gt;Long story short, shorten these commands like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias mycmd="my very very long command"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it's not permanent, it's limited to the current shell tab, to make it live forever in your system, open your shell config and write your aliases in it.&lt;/p&gt;

&lt;p&gt;So according to this, in my system (MacOS), I followed these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Step 1: run &lt;code&gt;code ~/.zshrc&lt;/code&gt; (&lt;code&gt;code&lt;/code&gt; opens up VScode editor, but you can use something else such as vim or nano)&lt;/li&gt;
&lt;li&gt;Step 2: write this command inside the opened file and save it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias dub="docker-compose up --build -d`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Step 3: you are done! open up &lt;strong&gt;a new shell&lt;/strong&gt; and use &lt;code&gt;dub&lt;/code&gt; command and it works totally the same.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And about VPNs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias ofv="sudo openfortivpn vpn.host.domain:port -u myusername -p mypassword --trusted-cert averyveryveryverylonghash"

alias opc="sudo openconnect -u myusername -p mypassword vpn.host.domain:port"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another alias I defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias ocp="oc port-forward"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define functions
&lt;/h2&gt;

&lt;p&gt;Sometimes, you need to define more than one command or you need to have some placeholders in your commands to keep those parts still general purpose.&lt;/p&gt;

&lt;p&gt;Let's say, sometimes you need some functions to do different operations and accept some inputs&lt;/p&gt;

&lt;h3&gt;
  
  
  Some examples
&lt;/h3&gt;

&lt;p&gt;When I want to instantiate a new Golang project, I should run these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir &amp;lt;my_project_name&amp;gt; 
cd &amp;lt;my_project_name&amp;gt;
touch main.go
go mod init &amp;lt;my_project_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest might be different but these four commands are always the same.&lt;/p&gt;

&lt;p&gt;I also have better solutions for this part of the article, but they are not in the context of this article and it's just an example.&lt;/p&gt;

&lt;p&gt;So, to simply those four commands and make them one, write a function like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gomake() {
    mkdir $1 
    cd $1
    touch main.go
    go mod init $1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I called this function &lt;code&gt;gomake&lt;/code&gt; and I can easily access it in my shell using &lt;code&gt;gomake &amp;lt;my_project_name&amp;gt;&lt;/code&gt; and it will do that 4 commands.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$1&lt;/code&gt; is a function argument, if you need more, you can access them by $2, $3, ...&lt;/p&gt;

&lt;p&gt;Note: you can use &lt;code&gt;echo "package main\n\nfunc main() {\n\t\n}" | cat &amp;gt; main.go&lt;/code&gt; instead of &lt;code&gt;touch main.go&lt;/code&gt; in Golang projects, this command simply make &lt;code&gt;main.go&lt;/code&gt; file and write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in it.&lt;/p&gt;

&lt;p&gt;Another example, using &lt;code&gt;oce &amp;lt;pod-name&amp;gt;&lt;/code&gt; instead of &lt;code&gt;oc exec &amp;lt;pod-name&amp;gt; -it -- sh&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oce() {
    oc exec $1 -it -- sh
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another example with 2 arguments,&lt;br&gt;
Sometimes I want to see the structure and some cool information about the projects (e.g. number of lines of code)&lt;br&gt;
For this case, I know two commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tree&lt;/code&gt; command, which is a tool to show directory structure of your projects, and it's pre-installed or you may install it using &lt;code&gt;brew install tree&lt;/code&gt; in mac.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cocnt&lt;/code&gt; which is a tool to count the number of lines of code, link to their github repo: &lt;a href="https://github.com/InnoFang/code-counter"&gt;https://github.com/InnoFang/code-counter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And I always forget the second! 😂 (what was it's command?)&lt;/p&gt;

&lt;p&gt;So for helping myself remembering the second command and first command flags, I wrote this functions and named it &lt;code&gt;struct&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct() {
    tree $1 -dCL $2 -I vendor
    cocnt search $1
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;About tree flags, &lt;code&gt;I&lt;/code&gt; is used for excluding a folder (vendor in my case), &lt;code&gt;d&lt;/code&gt; to show only directories, &lt;code&gt;L&lt;/code&gt; for level of going inside (which we get as an argument), &lt;code&gt;C&lt;/code&gt; for colorizing the output.&lt;/p&gt;

&lt;p&gt;So I call &lt;code&gt;struct &amp;lt;project-path&amp;gt; 2&lt;/code&gt; and it will print out the project with level two of directories without vendor folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Just if you are wondering (Used terms)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;oc&lt;/code&gt; is command used for working with Openshift clusters.&lt;/p&gt;

&lt;p&gt;Openshift is a platform made on top of Kubernetes for container orchestrations.&lt;/p&gt;

&lt;p&gt;Docker is a platform designed to help developers build, share, and run modern applications.&lt;/p&gt;

&lt;p&gt;To learn more about bash functions:&lt;br&gt;
&lt;a href="https://devqa.io/create-call-bash-functions/"&gt;https://devqa.io/create-call-bash-functions/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These aliases and functions are still useful beside all modern terminal tools such as fish or warp, etc.&lt;/p&gt;

&lt;p&gt;In addition to that, sometimes I write my own CLI tools or I use existing ones,&lt;/p&gt;

&lt;p&gt;In case of making a project (Golang in this article), templates are so useful and good alternative.&lt;/p&gt;

&lt;p&gt;Possibilities are endless...&lt;/p&gt;

&lt;p&gt;Finally, I hope you enjoyed reading this article and learned something useful.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>terminal</category>
      <category>shell</category>
    </item>
    <item>
      <title>How docker will save your time, and why should you learn it immediately. (2/2)</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Mon, 14 Nov 2022 07:23:48 +0000</pubDate>
      <link>https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-22-2eai</link>
      <guid>https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-22-2eai</guid>
      <description>&lt;p&gt;Hi guys!&lt;br&gt;
In the &lt;a href="https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-12-1ejk"&gt;last part&lt;/a&gt;, we discussed a little about what an image and a container is, in this part, we will make our own images and wrap our application in a container.&lt;/p&gt;
&lt;h2&gt;
  
  
  Make a Dockerfile in the root
&lt;/h2&gt;

&lt;p&gt;First of all, make a file named &lt;strong&gt;Dockerfile&lt;/strong&gt;, without any extension, in the root directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56vcfv47map69jvm03p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56vcfv47map69jvm03p8.png" alt="Dockerfile" width="391" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tip: you can call this file whatever you want, but &lt;strong&gt;Dockerfile&lt;/strong&gt; is the default recognizable name, other names, should be introduced in later steps.&lt;/p&gt;
&lt;h2&gt;
  
  
  Starting our image
&lt;/h2&gt;

&lt;p&gt;As I said before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Image is a collection of applications and commands running on a base image and this base image itself is a simplified Linux distro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And a Dockerfile, is an introduction file for our image.&lt;br&gt;
First of all, we should specify what base image we're going to run our application and commands on, and we do it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; base_image&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alpine latest version as base image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alpine specific version (3.15) with a pre-installed node.js with a specific version (18):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine3.15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you can find other base images and their tags (versions) in the Dockerhub.&lt;/p&gt;

&lt;p&gt;Tip: Always try to use tagged versions, even in the case of latest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command the image!
&lt;/h2&gt;

&lt;p&gt;You can make different users with different accessibilities in your image and run commands by their help, but for now, we're not going into that.&lt;/p&gt;

&lt;p&gt;You're already familiar with &lt;strong&gt;FROM&lt;/strong&gt; command that is used for pulling base image, there are more:&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;RUN&lt;/strong&gt;:&lt;br&gt;
The RUN instruction is used to run commands.&lt;br&gt;
From docker:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Executes any commands on top of the current image as a new layer and commit the results.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Commands could be for example &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;go mod tidy&lt;/code&gt; or &lt;code&gt;pip install -r requirements.txt&lt;/code&gt; or more complex commands like &lt;code&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y curl&lt;/code&gt; or any other command you run inside a linux!&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;CMD&lt;/strong&gt;:&lt;br&gt;
Provide defaults for an executing container, for example &lt;code&gt;npm run start&lt;/code&gt; or running a complied executable.&lt;/p&gt;

&lt;p&gt;Tip: there can only be one CMD instruction in a Dockerfile.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;COPY&lt;/strong&gt;:&lt;br&gt;
Copy files or folders from root project directory (called source) to a image's filesystem path (called dest).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# COPY source dest&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ui .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./&lt;/span&gt;
&lt;span class="c"&gt;# Or many files, last argument is dest&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod go.sum ./&lt;/span&gt;
&lt;span class="c"&gt;# Or&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ["go.mod", "go.sum", "./"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;WORKDIR&lt;/strong&gt;:&lt;br&gt;
The WORKDIR instruction sets the working directory for the next instructions that follow it in the Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="c"&gt;# Next commands will run in /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; file1 file2 ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; file3 file4 ./&lt;/span&gt;
&lt;span class="c"&gt;# now, we have /app/file1 /app/file2 etc.&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["./main"]&lt;/span&gt;
&lt;span class="c"&gt;# command above will look for /app/main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;ENV&lt;/strong&gt;: defines environment variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PG_PASS=12@3fl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;There are many other commands like &lt;strong&gt;EXPOSE&lt;/strong&gt;, &lt;strong&gt;ADD&lt;/strong&gt;, &lt;strong&gt;ENTRYPOINT&lt;/strong&gt; which you can read on &lt;a href="https://docs.docker.com/engine/reference/builder"&gt;Dockerfile reference&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build images
&lt;/h2&gt;

&lt;p&gt;Let's start with a node.js example, but don't worry if you're not a node.js developer.&lt;/p&gt;

&lt;p&gt;After writing a complete Dockerfile like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine3.15&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; npm run start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: package*.json means all files starting with &lt;strong&gt;package&lt;/strong&gt; and ending with &lt;strong&gt;.json&lt;/strong&gt; =&amp;gt; package.json and package-lock.json&lt;/p&gt;

&lt;p&gt;We can build the image by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We usually run this command inside project root directory and use a single dot . for path: &lt;code&gt;docker build .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command alone, assign a random name for our container, but we can name it on our own using tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; &amp;lt;image_name&amp;gt; &amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caching and layered images
&lt;/h2&gt;

&lt;p&gt;Last version will work, but is not performant, it's highly recommended to consider caching techniques.&lt;/p&gt;

&lt;p&gt;Docker images are layered, simply said, every line in Dockerfile is a layer, and Dockerfile is read line by line.&lt;/p&gt;

&lt;p&gt;What do we cache in the world of docker? &lt;br&gt;
Mostly, project dependencies and packages and also we do not COPY them from source to destination.&lt;/p&gt;

&lt;p&gt;As you might know, &lt;code&gt;npm i&lt;/code&gt; command is a so heavy command that installs project dependencies and it read dependency needs from package.json file.&lt;/p&gt;

&lt;p&gt;Look at example below:&lt;br&gt;
project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- index.js
- node_modules (dependencies)
- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; index.js package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; npm run start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's good and working, but what happens if we change package.json (we add new dependency)&lt;/p&gt;

&lt;p&gt;They will install again and that's OK.&lt;/p&gt;

&lt;p&gt;But what happens if we change index.js &lt;strong&gt;without&lt;/strong&gt; changing dependencies?&lt;br&gt;
Dependencies will install again! and that's so NOT OK!&lt;/p&gt;

&lt;p&gt;And that happens because we copy package.json and index.js at the same time, and we do installation after that.&lt;/p&gt;

&lt;p&gt;We should copy all files except dependency introducer (pakcage.json) after installing dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; index.js ./&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; npm run start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's way much faster!&lt;/p&gt;

&lt;p&gt;in this case, if we change only index.js, docker will read Dockerfile from line 3 and go after that, because it's defined on line 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running your image (container)
&lt;/h2&gt;

&lt;p&gt;Now we've learned how to make custom images, and we know how to run a container or expose ports from &lt;a href="https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-12-1ejk"&gt;last tutorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Running your own container is the same as running a Redis or Postgres container.&lt;br&gt;
You can also make your own Redis or Postgres image!&lt;/p&gt;

&lt;h2&gt;
  
  
  Exposing port
&lt;/h2&gt;

&lt;p&gt;A container is an isolated environment, that means, all ports are closed by default.&lt;br&gt;
If you have a http server running inside a container, you should open (expose) your preferred port.&lt;br&gt;
There is a &lt;strong&gt;EXPOSE&lt;/strong&gt; instruction, but I personally prefer using &lt;code&gt;-p &amp;lt;port&amp;gt;:&amp;lt;port&amp;gt;&lt;/code&gt; when running a container in most cases, this actually overwrites &lt;strong&gt;EXPOSE&lt;/strong&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources and Final quote
&lt;/h2&gt;

&lt;p&gt;I tried to help you understand that docker is not a challenge, it's a tool to make your life easier, this part covered basics of writing a Dockerfile and how to make your custom images.&lt;/p&gt;

&lt;p&gt;There are so many tutorials out there, but I'm gonna suggest the ones that I enjoyed the most.&lt;br&gt;
As an instruction that show how containerization will help us: &lt;a href="https://www.youtube.com/watch?v=0qotVMX-J5s&amp;amp;list=PLOspHqNVtKABAVX4azqPIu6UfsPzSu2YN&amp;amp;index=2"&gt;Containerization explained&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.udemy.com/course/docker-and-kubernetes-the-complete-guide"&gt;Docker and Kubernetes course by Stephan Grider&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to make a simple interactive shell in Go</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Tue, 06 Sep 2022 00:54:23 +0000</pubDate>
      <link>https://dev.to/arshamalh/how-to-make-a-simple-interactive-shell-in-go-2log</link>
      <guid>https://dev.to/arshamalh/how-to-make-a-simple-interactive-shell-in-go-2log</guid>
      <description>&lt;p&gt;What is more exciting than making real-world applications? 🤔&lt;br&gt;
for me, it's teaching people how to make them again!&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Study
&lt;/h2&gt;

&lt;p&gt;As I've spoken about my Dockeroller project earlier in my articles, it's a project that help you control your docker deamon through different gates, such as Telegram or API.&lt;/p&gt;

&lt;p&gt;I realized this gates should be easily configurable by user,&lt;br&gt;
We should be able to turn some gates on or off, change their tokens, ports, and passwords, etc.&lt;br&gt;
One approach, was using &lt;a href="https://github.com/spf13/viper" rel="noopener noreferrer"&gt;Viper&lt;/a&gt; and dockeroller.yml file (implementing and teaching this approach is in my todo list)&lt;/p&gt;

&lt;p&gt;Another approach, can be an interactive shell!&lt;br&gt;
Let's do it!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Completed code is available in my Github gists &lt;a href="https://gist.github.com/arshamalh/819afbbe6fb2d31a8040096eb71f5de3" rel="noopener noreferrer"&gt;(Link)&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Welcome to the stage!
&lt;/h2&gt;

&lt;p&gt;Try to be clean by separating things!&lt;br&gt;
In this case, I separated my code into different stages,&lt;br&gt;
such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Welcome stage&lt;/li&gt;
&lt;li&gt;Help stage&lt;/li&gt;
&lt;li&gt;Gates stage&lt;/li&gt;
&lt;li&gt;Telegram&lt;/li&gt;
&lt;li&gt;API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each stage has a message that we defined using constants at the beginning of the code, in bigger projects, they could be placed in for example a &lt;code&gt;msg&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;We used backtick for multiline strings and we wrote constant type only once because all of them are in same type.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;msg_welcome&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`
Welcome to Dockeroller!
It's sample multiline!
`&lt;/span&gt;

    &lt;span class="n"&gt;msg_help&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`
Dockeroller is an open-source project made for fun.
It's sample multiline!
`&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Do it forever!
&lt;/h2&gt;

&lt;p&gt;The simplest form of interactive shells, use an infinite loop and it iterates until you break it,&lt;br&gt;
But don't worry, it's not bad at all, I'll tell you why.&lt;/p&gt;

&lt;p&gt;In any iteration, we get something new from the user, in that time, our app is not consuming any resource,&lt;br&gt;
After passing desired input to the shell, it'll process the result and go to the next iteration.&lt;br&gt;
Actually, our shell is constantly sleeping between iterations, it's waiting for us to pass it our input.&lt;/p&gt;

&lt;p&gt;Have a look at this code:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StageWelcome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StageHelp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StageGates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StageTelegram&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StageAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Functions started with the word &lt;code&gt;StageXxx()&lt;/code&gt; are our handlers, they handle what happens in (on 😅) a stage, we'll get into them soon.&lt;/p&gt;

&lt;p&gt;Also it may be clear that any stage is assigned to a number, but it could be assigned to anything else, but that may not be needed for a project this size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As a recap&lt;/strong&gt;&lt;br&gt;
We have a for loop, we iterate over it and in every iteration, we check which stage we are on (using switch) and handle that stage. &lt;/p&gt;

&lt;p&gt;Also, we update our stage after each iteration, but why?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where would you like to go after?
&lt;/h2&gt;

&lt;p&gt;It's time to update our welcome message!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;msg_welcome&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`
Welcome to Dockeroller!
Where would you like to go after? (choose only number)
1 - help
2 - gates
`&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So we let user decide which stage is its next place!&lt;br&gt;
and it's the reason we update stage every time.&lt;br&gt;
Updating &lt;code&gt;stage&lt;/code&gt; variable is a part of navigating between Stages.&lt;br&gt;
And each handler, according to its inputs, will decide where we would go next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shell input &amp;amp; output
&lt;/h2&gt;

&lt;p&gt;What is the point of this article without going into terminal itself?&lt;br&gt;
This is just so easy, you may know how to use &lt;code&gt;fmt.Print()&lt;/code&gt; function, it Prints something on the terminal, &lt;strong&gt;Without any default formatting&lt;/strong&gt;.&lt;br&gt;
There are some other variants of it such as &lt;code&gt;fmt.Println()&lt;/code&gt; for printing with a line break and &lt;code&gt;fmt.Printf()&lt;/code&gt; for printing with a specified format.&lt;/p&gt;

&lt;p&gt;OK, there are a few more functions in &lt;code&gt;fmt&lt;/code&gt; package, here we need &lt;code&gt;fmt.Scanln()&lt;/code&gt; or &lt;code&gt;fmt.Scan()&lt;/code&gt; (there is also a &lt;code&gt;fmt.Scanf()&lt;/code&gt; for scanning according to a specified format)&lt;/p&gt;

&lt;p&gt;Let's have a very simple example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scanln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't pass pointer to Scanln, it won't have any effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can add extra print statements to make it more beautiful.&lt;br&gt;
We can also pass multiple pointers of different types to it, Scan will separate them by space and then populate them.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Just for beauty&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scanln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"you're"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"years old."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Output will be like:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggjw9vs5oa9i50gporgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggjw9vs5oa9i50gporgl.png" alt="go interactive shell result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Handlers
&lt;/h2&gt;

&lt;p&gt;I think this should make sense now:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="c"&gt;// Welcome stage handler&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;StageWelcome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_welcome&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;getStage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Help stage handler&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;StageHelp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_help&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;getStage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Helper function for asking stage number and return it for next decisions&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getStage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scanln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you think it's not clear, I suggest you to put this codes together now and then move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gates handlers
&lt;/h2&gt;

&lt;p&gt;Welcome is a first level stage&lt;br&gt;
Help and Gates are Second level&lt;br&gt;
Telegram &amp;amp; API are third level&lt;br&gt;
and there can be more levels.&lt;/p&gt;

&lt;p&gt;How can we realize it?&lt;br&gt;
well, there are many algorithms for it, but here, if we are in gates stage and we should go on with option 1 (telegram) or 2 (api) I add 10 to stage number, and in main switch, telegram will be 11 and api will be 12.&lt;br&gt;
if we want to come back from this level, we will return 0 that means Welcome (stage) handler.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;StageGates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_gates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;getStage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Telegram &amp;amp; API handlers&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I just explain one of them, follow the same approach.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;StageTelegram&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_telegram&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Get a value (token) &lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;getInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Token: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Get another value (username) &lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;getInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Username: @"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// Telegram usernames start with @,&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// Some users may include it, some may not,&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// So we helped users by including it.&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// And username variable won't have @ in it.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Username and token successfully sat!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c"&gt;// Return to the main menu after succefull config&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Helper function to print a message and get a value (by populating a pointer)&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scanln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// DO NOT include &amp;amp;, because it's a pointer when is passed to this function!&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Final quote&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this article, feel free to share your thoughts and critics with me.&lt;br&gt;
For more beautiful UIs, you can use this open source package: &lt;a href="https://github.com/manifoldco/promptui" rel="noopener noreferrer"&gt;promptui&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>shell</category>
      <category>dockeroller</category>
    </item>
    <item>
      <title>How docker will save your time, and why should you learn it immediately. (1/2)</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Thu, 01 Sep 2022 19:20:09 +0000</pubDate>
      <link>https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-12-1ejk</link>
      <guid>https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-12-1ejk</guid>
      <description>&lt;p&gt;What is Docker? And why is it popular?&lt;br&gt;
Everywhere on the internet you find articles about how docker is compared with VM and diagrams like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhy8u4o80i4m4wm384vf3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhy8u4o80i4m4wm384vf3.jpg" alt="Docker VS VM" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I'm going to teach you Docker &lt;strong&gt;just as a tool&lt;/strong&gt;, so it will be so easier to understand, and we don't dissect it's underlying functionality a lot (we do it just a few 😅).&lt;/p&gt;
&lt;h2&gt;
  
  
  Don't install new apps! just pull them!
&lt;/h2&gt;

&lt;p&gt;The most interesting thing about docker for a beginner, is the ability to pull different tools so easily.&lt;br&gt;
&lt;a href="https://hub.docker.com"&gt;DockerHub&lt;/a&gt; will be like the App Store!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5hwwe6p6j4ug6p8r9lc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5hwwe6p6j4ug6p8r9lc.png" alt="Docker app store!" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see, we can pick up any app that we want, actually we call them images in the world of Docker.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is an image?
&lt;/h2&gt;

&lt;p&gt;Image is a collection of applications and commands running on a base image and this base image itself is a simplified Linux distro.&lt;br&gt;
This Linux doesn't have a GUI and could be any distro such as Ubuntu, Alpine, Bullseye, etc.&lt;/p&gt;

&lt;p&gt;For example, you can install almost any version of any database such as Postgres, Redis, etc, by pulling their image and run them as a container.&lt;br&gt;
You can have multiple versions of the same application at the same time.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is a container?
&lt;/h2&gt;

&lt;p&gt;Image itself can be supposed as an executable file, it is nothing unless you run it, anytime you run it, a container (process) will be made.&lt;br&gt;
you can run many same containers using an image.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting dirty with Redis!
&lt;/h2&gt;

&lt;p&gt;Let's have a hands-on experience with Redis,&lt;br&gt;
Go to &lt;a href="https://hub.docker.com/_/redis"&gt;this link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fielk3jcuxovx57pigcc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fielk3jcuxovx57pigcc4.png" alt="Redis dockerhub" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this picture, &lt;br&gt;
Tags can be assumed as different version of images, tag name may include base image name and its version.&lt;/p&gt;

&lt;p&gt;Official images are famous projects that are being made constantly by docker team, actually everyone including you and me, can make an image and push it on Dockerhub as a public or private docker image.&lt;/p&gt;

&lt;p&gt;At the top right, you can see &lt;code&gt;docker pull redis&lt;/code&gt; command, it's the simplest way to pull this image, but we can find more detailed commands at the bottom of that page.&lt;/p&gt;

&lt;p&gt;For example this command will pull the &lt;code&gt;redis&lt;/code&gt; image and run a container called "my-redis-container":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; my-redis-container &lt;span class="nt"&gt;-d&lt;/span&gt; redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-d&lt;/code&gt; is used for detaching the process, it will run this container and leave the shell alone for your future use.&lt;/p&gt;

&lt;p&gt;But you're not able to use this container, you should expose the Redis port.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; my-redis-container &lt;span class="nt"&gt;-p&lt;/span&gt; 6379:6379 &lt;span class="nt"&gt;-d&lt;/span&gt; redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-p 6379:6379&lt;/code&gt; is a port mapping that maps port 6379 of the container to the 6379 of our localhost.&lt;br&gt;
And you can now access Redis through localhost:6379&lt;/p&gt;

&lt;h2&gt;
  
  
  What other things can I do?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Are you a windows user but you like to use Linux without getting into the trouble of VM or Double boot?
Run this command:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; itubu &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make a container named "itubu" and connect your shell to its shell.&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvl7ts81yrtuhhh8q80m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvl7ts81yrtuhhh8q80m.png" alt="running ubuntu in docker" width="755" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the "run" command, first look in your local to see if there is any image called "ubuntu", then if it doesn't exists, docker will pull it from Dockerhub.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you want to use Tor network without getting into the trouble of configuring tor?
Run this command:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8118:8118 &lt;span class="nt"&gt;-p&lt;/span&gt; 9050:9050 &lt;span class="nt"&gt;-d&lt;/span&gt; dperson/torproxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;dperson/torproxy is an unofficial docker image.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-p 8118:8118&lt;/code&gt; (and &lt;code&gt;-p 9050:9050&lt;/code&gt;) is a port mapping that maps port 8118 of container to the 8118 of our localhost.&lt;/p&gt;

&lt;p&gt;Now you can proxy your requests through Tor network using this ports.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you want to use a headless browser?
Run this command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 browserless/chrome
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll have a chrome browser on localhost:3000&lt;br&gt;
It could be so helpful for scrapping.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We spoke about databases before 😄 and there are so many other usecases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  It mostly needs no effort
&lt;/h2&gt;

&lt;p&gt;Docker itself plays an important role in DevOps world, and without a doubt, it has so many tips and tricks.&lt;br&gt;
But in most cases, as a beginner, you will just need a one line command or a 10 line Dockerfile, to make your project way much better.&lt;br&gt;
The advantages of using Docker is explained in a video I added to the end of this article and I'm not covering them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other resources
&lt;/h2&gt;

&lt;p&gt;There are so many tutorials out there, but I'm gonna suggest the ones that I enjoyed the most.&lt;br&gt;
As an instruction that show how containerization will help us: &lt;a href="https://www.youtube.com/watch?v=0qotVMX-J5s&amp;amp;list=PLOspHqNVtKABAVX4azqPIu6UfsPzSu2YN&amp;amp;index=2"&gt;Containerization explained&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.udemy.com/course/docker-and-kubernetes-the-complete-guide"&gt;Docker and Kubernetes course by Stephan Grider&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final quote
&lt;/h2&gt;

&lt;p&gt;I tried to help you understand that docker is not a challenge, it's a tool to make your life easier, this part included some cool stuff, &lt;a href="https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-22-2eai"&gt;next part&lt;/a&gt; we will cover basics of writing a Dockerfile and how to make your custom images.&lt;/p&gt;

&lt;p&gt;Next Part: &lt;a href="https://dev.to/arshamalh/how-docker-will-save-your-time-and-why-should-you-learn-it-immediately-22-2eai"&gt;How docker will save your time, and why should you learn it immediately. (2/2)&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>[TechStory]: Trying to shutdown a gin server... (goroutines and channels tips)</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Thu, 01 Sep 2022 09:59:26 +0000</pubDate>
      <link>https://dev.to/arshamalh/trying-to-shutdown-a-gin-server-goroutines-and-channels-tips-gf3</link>
      <guid>https://dev.to/arshamalh/trying-to-shutdown-a-gin-server-goroutines-and-channels-tips-gf3</guid>
      <description>&lt;p&gt;Today, I was trying to gracefully shutdown my gin server and start it again through the application itself, without re-running my application.&lt;br&gt;
I learned some precious things that I'd really love to share with you.&lt;/p&gt;
&lt;h2&gt;
  
  
  So, What's the problem?
&lt;/h2&gt;

&lt;p&gt;Running a server, using &lt;code&gt;gin.Run()&lt;/code&gt; or &lt;code&gt;http.ListenAndServe()&lt;/code&gt;, will block goroutine, if it's in the main process, so it will block the main goroutine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ginApp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;ginApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":80"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// This code is blocking&lt;/span&gt;
  &lt;span class="c"&gt;// next lines will never run because of blocking code.&lt;/span&gt;
  &lt;span class="n"&gt;FuncForStoppingGinServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// This function can't be used.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use another goroutine
&lt;/h2&gt;

&lt;p&gt;We can simply block another goroutine and help main goroutine to remain free.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ginApp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;ginApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":80"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// This code is not blocking anymore.&lt;/span&gt;
  &lt;span class="n"&gt;FuncForStoppingGinServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// This function will run now.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, what should we do inside &lt;code&gt;FuncForStoppingGinServer()&lt;/code&gt;??&lt;/p&gt;

&lt;p&gt;Nothing!&lt;br&gt;
The answer is that gin itself doesn't have any function for shutting down its server!&lt;br&gt;
But before getting into that, let's try another wrong way!!&lt;/p&gt;
&lt;h2&gt;
  
  
  Just kill it!
&lt;/h2&gt;

&lt;p&gt;Are you thinking about stopping your gin server using goroutines and channels? (forget about handling active connections for now)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ginApp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Engine&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Make an engine&lt;/span&gt;
  &lt;span class="n"&gt;ginApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c"&gt;// Make a stop channel&lt;/span&gt;
  &lt;span class="n"&gt;stopChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

  &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ginApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":80"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// blocking process&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt; 1 &amp;lt;&amp;lt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;stopChan&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}()&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt; 2 &amp;lt;&amp;lt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c"&gt;// terminate gin server after 3 seconds&lt;/span&gt;
  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;stopChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{}&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt; 3 &amp;lt;&amp;lt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sounds to be a good approach, but what do you think is wrong here?&lt;/p&gt;

&lt;p&gt;Which numbers will be printed? (1, 2, 3)?&lt;/p&gt;

&lt;p&gt;As I mentioned before, &lt;code&gt;ginApp.Run(":80")&lt;/code&gt; is a blocking process and it blocks its goroutine, so we will send to channel &lt;code&gt;stopChan&lt;/code&gt;, &lt;br&gt;
BUT, &lt;br&gt;
we will never be able to &lt;strong&gt;read&lt;/strong&gt; from the &lt;code&gt;stopChan&lt;/code&gt; using our &lt;code&gt;for range loop&lt;/code&gt;, because that came after a blocking process and "&amp;gt;&amp;gt; 1 &amp;lt;&amp;lt;" will not be printed.&lt;/p&gt;

&lt;p&gt;And as our channel is not buffered, sender that is main goroutine also will be blocked until somebody read from that!, exactly before printing "&amp;gt;&amp;gt; 3 &amp;lt;&amp;lt;" and it will not be printed too.&lt;/p&gt;

&lt;p&gt;"&amp;gt;&amp;gt; 2 &amp;lt;&amp;lt;" will be printed anyway 😄&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Additional fun fact:&lt;/strong&gt; If we make our channel buffered (size 1 is enough for this case), main goroutine will send to it and go ahead, then it will complete its work and close, whenever main goroutine job is done, the whole program exists! and any other goroutine will die with it, just make this change and see the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;stopChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also should mention that &lt;code&gt;chan struct{}&lt;/code&gt; as the channel type and empty struct &lt;code&gt;struct{}{}&lt;/code&gt; will consume no memory at all, and it's known as signal only channel.&lt;/p&gt;

&lt;p&gt;I finally realized there is no way to solve this problem this way:&lt;br&gt;
&lt;a href="https://stackoverflow.com/a/20429950/12972198"&gt;Is there a way to stop a long blocking function?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also learn more about stopping goroutines in this Question: &lt;a href="https://stackoverflow.com/questions/6807590/how-to-stop-a-goroutine"&gt;How to stop a goroutine&lt;/a&gt;&lt;br&gt;
And I'll cover more examples later. (you can follow me to get noticed)&lt;/p&gt;
&lt;h2&gt;
  
  
  Back into the problem!
&lt;/h2&gt;

&lt;p&gt;So using Goroutines didn't solved our problem,&lt;br&gt;
How about trying &lt;code&gt;http.Server.Shutdown()&lt;/code&gt; method?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ginApp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Engine&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Make an engine&lt;/span&gt;
  &lt;span class="n"&gt;ginApp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c"&gt;// Make a http server&lt;/span&gt;
  &lt;span class="n"&gt;httpServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;":80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ginApp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Launch http server in a separate goroutine&lt;/span&gt;
  &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c"&gt;// Stop the server&lt;/span&gt;
  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"We're going to stop gin server"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It may be helpful to read this question: &lt;a href="https://stackoverflow.com/questions/65686384/graceful-stop-of-gin-server"&gt;Graceful stop of gin server&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It works, but what is still wrong?
&lt;/h2&gt;

&lt;p&gt;Now, we are shutting down our server inside of our program, but how can we start it again?&lt;br&gt;
Maybe by running &lt;code&gt;ListenAndServe()&lt;/code&gt; again?&lt;/p&gt;

&lt;p&gt;As I asked in this question: &lt;a href="https://stackoverflow.com/questions/73563023/how-to-stop-and-start-gin-server-multiple-times-in-one-run"&gt;How to stop and start gin server multiple times in one run&lt;/a&gt;&lt;br&gt;
I'm trying to implement something like this semi-code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's do it by a little refactor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;httpServer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHTTPServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// Simulate other processes&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewHTTPServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;":80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;&amp;gt;&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this code and see what happens!&lt;br&gt;
Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;Gin&lt;/span&gt; &lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="n"&gt;closed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What? we called srv.Stop() just once, but our server closed twice!&lt;br&gt;
Why?&lt;br&gt;
According to .Shutdown() functions docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Once Shutdown has been called on a server, it may not be reused; future calls to methods such as Serve will return ErrServerClosed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, it's officially not working!&lt;/p&gt;

&lt;p&gt;But there is still one little change, we can make the server struct again from scratch, every time we start it.&lt;/p&gt;

&lt;p&gt;Add a serve function to the last code and change main function, other codes are the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// Simulate other processes&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewHTTPServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c"&gt;// Register handlers or other stuff&lt;/span&gt;
  &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is something that we want, but you can make the code cleaner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other solutions
&lt;/h2&gt;

&lt;p&gt;In my case, I was able to use Fiber instead, it fits way much better in my projects, but this may not be the solution you are looking for,&lt;br&gt;
Also you can have a look at this page: &lt;a href="https://chenyitian.gitbooks.io/gin-web-framework/content/docs/38.html"&gt;Graceful restart or stop&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final quote
&lt;/h2&gt;

&lt;p&gt;This article had a different feeling for myself, it was a up and down path with some tips and some not working approaches, I hope you feel the same and I'll be happy hear your thoughts.&lt;/p&gt;

</description>
      <category>go</category>
      <category>goroutines</category>
      <category>channels</category>
      <category>gin</category>
    </item>
    <item>
      <title>How to Unmarshal JSON in a custom way in Golang</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Thu, 04 Aug 2022 13:39:28 +0000</pubDate>
      <link>https://dev.to/arshamalh/how-to-unmarshal-json-in-a-custom-way-in-golang-42m5</link>
      <guid>https://dev.to/arshamalh/how-to-unmarshal-json-in-a-custom-way-in-golang-42m5</guid>
      <description>&lt;p&gt;When I was working on &lt;a href="https://github.com/arshamalh/gocoinex"&gt;gocoinex library&lt;/a&gt; for the first time, I needed some custom configuration on JSON unmarshalling process, I want to share my learnings with you here, but before that, we're going to have a recap on how we can unmarshall JSON in golang.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These are real world examples. (coinex exchange API)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we make our request like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.coinex.com/v1/market/list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we'll get a json object like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"LTCBCH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ETHBCH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ZECBCH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"DASHBCH"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we should parse it,&lt;br&gt;
There are different ways to parse it,&lt;br&gt;
You can use &lt;strong&gt;NewDecoder&lt;/strong&gt; or &lt;strong&gt;Unmarshal&lt;/strong&gt; functions of &lt;strong&gt;json&lt;/strong&gt; package,&lt;br&gt;
and you can decode it to a &lt;code&gt;struct&lt;/code&gt; or to a &lt;code&gt;map[string]interface{}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It depends on your preferences, but in this case, I prefer NewDecoder and struct combination.&lt;/p&gt;

&lt;p&gt;So we should make a struct like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AllMarketList&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"code"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
    &lt;span class="n"&gt;Data&lt;/span&gt;    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also we can have embedded structs, for example, we break last struct to two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;GeneralResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"code"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AllMarketList&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;GeneralResponse&lt;/span&gt;
    &lt;span class="n"&gt;Data&lt;/span&gt;    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there is no difference.&lt;/p&gt;

&lt;p&gt;Finally, use NewDecoder to decode the raw_response to AllMarketList struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;allMarketList&lt;/span&gt; &lt;span class="n"&gt;AllMarketList&lt;/span&gt;
&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;allMarketList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Completed code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AllMarketList&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"code"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
    &lt;span class="n"&gt;Data&lt;/span&gt;    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://api.coinex.com/v1/market/list"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;allMarketList&lt;/span&gt; &lt;span class="n"&gt;AllMarketList&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;allMarketList&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%+v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allMarketList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Two
&lt;/h2&gt;

&lt;p&gt;Think we have a json like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1513865441609&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;returning&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ticker"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"open"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;highest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;price&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"last"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;latest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;price&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="nl"&gt;"vol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"110"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="err"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;volume&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ok"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're going to improve some things in decoding process&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In this case, Unix timestamp can't be parsed, we should provide it a way.&lt;/li&gt;
&lt;li&gt;We want to remove "ticker" key and access to "open", "last", "vol" directly from "data".&lt;/li&gt;
&lt;li&gt;"last" should be exported to field named "Close"! (same happens with "vol" and "Volume".&lt;/li&gt;
&lt;li&gt;"open", "last", "vol" should be float, not string, but we'll leave them for next example.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Problems 1 and 2, can be solved by implementing UnmarshalJSON method on any struct we want to decode.&lt;br&gt;
problem 3 will be easily solved with json tags. (I've mentioned it in the code below)&lt;/p&gt;

&lt;p&gt;Our final struct should be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Final struct&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SingleMarketStatistics&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;    &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"code"`&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"message"`&lt;/span&gt;
    &lt;span class="n"&gt;Data&lt;/span&gt;    &lt;span class="n"&gt;TickerData&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Inner struct that we should implement to solve problem 2&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;TickerData&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ServerTime&lt;/span&gt; &lt;span class="n"&gt;CTime&lt;/span&gt;   &lt;span class="s"&gt;`json:"date"`&lt;/span&gt; &lt;span class="c"&gt;// CTime is short for CustomTime&lt;/span&gt;
    &lt;span class="n"&gt;Open&lt;/span&gt;       &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"open"`&lt;/span&gt;
    &lt;span class="n"&gt;Close&lt;/span&gt;      &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"last"`&lt;/span&gt; &lt;span class="c"&gt;// Different Attribute name and tag name&lt;/span&gt;
    &lt;span class="n"&gt;Volume&lt;/span&gt;     &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"vol"`&lt;/span&gt; &lt;span class="c"&gt;// Different Attribute name and tag name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Custome time&lt;/span&gt;
&lt;span class="c"&gt;// Inner struct that we should implement to solve problem 1&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CTime&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Custom time implementation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;CTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UnmarshalJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Ignore null, like in the main JSON package.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"null"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;`""`&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// Fractional seconds are handled implicitly by Parse.&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixMilli&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CTime&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we don't get an error anymore!&lt;br&gt;
This method will be automatically used (thanks to interfaces!) whenever we want to decode a time to CTime!&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom Data implementation
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;TickerData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UnmarshalJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"null"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;`""`&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// This is how this json really looks like.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;realTicker&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ServerTime&lt;/span&gt; &lt;span class="n"&gt;CTime&lt;/span&gt; &lt;span class="s"&gt;`json:"date"`&lt;/span&gt;
        &lt;span class="n"&gt;Ticker&lt;/span&gt;     &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// tags also can be omitted when we're using UnmarshalJSON.&lt;/span&gt;
            &lt;span class="n"&gt;Open&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"open"`&lt;/span&gt;
            &lt;span class="n"&gt;Close&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"last"`&lt;/span&gt;
            &lt;span class="n"&gt;Volume&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"vol"`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"ticker"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Unmarshal the json into the realTicker struct.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;realTicker&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Set the fields to the new struct,&lt;/span&gt;
    &lt;span class="c"&gt;// with any shape it has,&lt;/span&gt;
    &lt;span class="c"&gt;// or anyhow you want.&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TickerData&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ServerTime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;realTicker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;realTicker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;realTicker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Volume&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;realTicker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Volume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, just use NewDecoder as before, no change is needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;singleMarketStatistics&lt;/span&gt; &lt;span class="n"&gt;SingleMarketStatistics&lt;/span&gt; 
&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;allMarketList&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Three
&lt;/h2&gt;

&lt;p&gt;Imagine a JSON like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"asks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;asks&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ask&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"10.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ask&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"0.999"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Amount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ONE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ask&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bids"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Same&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;structure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;asks&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"10.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"1.000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it's totally clear, in the non professional way, we should decode "asks" to &lt;code&gt;[][]string&lt;/code&gt; and access first ask price like this &lt;code&gt;asks[0][0]&lt;/code&gt; and amount &lt;code&gt;asks[0][1]&lt;/code&gt;&lt;br&gt;
Who remembers 0 is price and 1 is amount? What was which? 😄&lt;br&gt;
So we'll manage them on the UnmarshalJSON method.&lt;br&gt;
Also, we'll solve problem 4 of previous example that also exists here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;BidAsk&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Tags are not needed.&lt;/span&gt;
    &lt;span class="n"&gt;Price&lt;/span&gt;  &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"price"`&lt;/span&gt;  &lt;span class="c"&gt;// Bid or Ask price&lt;/span&gt;
    &lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"amount"`&lt;/span&gt; &lt;span class="c"&gt;// Bid or Ask amount&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;BidAsk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UnmarshalJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Ignore null, like in the main JSON package.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"null"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;`""`&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Unmarshal to real type.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bisask&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;bisask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Change value type from string to float64.&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bisask&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bisask&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Map old structure to new structure.&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BidAsk&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MarketDepth&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Asks&lt;/span&gt;   &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;BidAsk&lt;/span&gt; &lt;span class="s"&gt;`json:"asks"`&lt;/span&gt; &lt;span class="c"&gt;// Ask depth&lt;/span&gt;
    &lt;span class="n"&gt;Bids&lt;/span&gt;   &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;BidAsk&lt;/span&gt; &lt;span class="s"&gt;`json:"bids"`&lt;/span&gt; &lt;span class="c"&gt;// Bid depth&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, we simply use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;marketDepth&lt;/span&gt; &lt;span class="n"&gt;MarketDepth&lt;/span&gt; 
&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;marketDepth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And enjoy the beauty of your result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Asks&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ask %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  Price: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// here is the beauty&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  Amount: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// here is the beauty&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bids&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bid %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  Price: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// here is the beauty&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  Amount: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// here is the beauty&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
    </item>
    <item>
      <title>How to use Docker Multistage to make tiny images (TS and Golang)</title>
      <dc:creator>Mohammad Reza Karimi</dc:creator>
      <pubDate>Wed, 03 Aug 2022 23:09:14 +0000</pubDate>
      <link>https://dev.to/arshamalh/how-to-use-docker-multistage-to-make-tiny-images-ts-and-golang-g4j</link>
      <guid>https://dev.to/arshamalh/how-to-use-docker-multistage-to-make-tiny-images-ts-and-golang-g4j</guid>
      <description>&lt;p&gt;Have you ever wondered how you can remove redundant build dependencies from your docker image?&lt;/p&gt;

&lt;p&gt;Did you know your image can be easily optimized?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We're not much language-related in this article, and reading all examples can be beneficial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TS example
&lt;/h2&gt;

&lt;p&gt;For example, maybe you've always been using this kind of Dockerfile to build and run your Typescript project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine3.15&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; tsconfig.json .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;, &lt;span class="s2"&gt;"run"&lt;/span&gt;, &lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "run", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, but it can be smaller without losing anything important,&lt;br&gt;
Because, on the line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;, &lt;span class="s2"&gt;"run"&lt;/span&gt;, &lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are converting some TS codes to JS codes with some Tools (dev dependencies)&lt;br&gt;
What happens if we remove those tools after conversion? Nothing!&lt;/p&gt;

&lt;p&gt;Have a look at picture below, we've built our image in three stages, instead of one, and we saved 35% of space!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4htns2axmh87lieoclw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4htns2axmh87lieoclw.png" alt="optimizing docker builds with multistage builds" width="702" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ts-compiler&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; tsconfig.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;
&lt;span class="c"&gt;# Build the project (TS to JS conversion)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;, &lt;span class="s2"&gt;"run"&lt;/span&gt;, &lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ts-remover&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="c"&gt;# We need package.json again&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ts-compiler /usr/app/package*.json ./&lt;/span&gt;
&lt;span class="c"&gt;# Move built codes from last stage here&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ts-compiler /usr/app/build ./&lt;/span&gt;
&lt;span class="c"&gt;# We don't need dev dependencies anymore&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev

&lt;span class="c"&gt;# Using google optimized containers can make it even smaller&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gcr.io/distroless/nodejs:18&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ts-remover /usr/app ./&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 1000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Be careful about environment variables
&lt;/h2&gt;

&lt;p&gt;Imagine you are using a special package, for example &lt;strong&gt;Puppeteer&lt;/strong&gt;&lt;br&gt;
Puppeteer will download a chrome browser when you're installing it, but you can disable it if you want, by setting a ENV.&lt;br&gt;
Have a look at the change we made on stage one of last code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ts-compiler&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .&lt;/span&gt;

&lt;span class="c"&gt;# This line is added 👇🏻&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; tsconfig.json .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;, &lt;span class="s2"&gt;"run"&lt;/span&gt;, &lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you run multistage build again, you'll see a huge increment 😳&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx980s9lt79fuob150vl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx980s9lt79fuob150vl.png" alt="Increment after multistage" width="573" height="116"&gt;&lt;/a&gt;&lt;br&gt;
What is happening?&lt;br&gt;
The fact is, you should use ENV and ARG commands per Stage, we are installing dependencies twice in two stage, so we should skip chrome installation twice!&lt;br&gt;
Nothing talks more than a piece of code 😄:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ts-compiler&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json .&lt;/span&gt;

&lt;span class="c"&gt;# Define ENV once here&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; tsconfig.json .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;, &lt;span class="s2"&gt;"run"&lt;/span&gt;, &lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ts-remover&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ts-compiler /usr/app/package.json .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ts-compiler /usr/app/build .&lt;/span&gt;

&lt;span class="c"&gt;# Define ENV once again!&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--omit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev

&lt;span class="c"&gt;# We don't need that ENV in this stage, &lt;/span&gt;
&lt;span class="c"&gt;# because we're not installing anything more.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gcr.io/distroless/nodejs:18&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=ts-remover /usr/app ./&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; 1000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["index.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Go example
&lt;/h2&gt;

&lt;p&gt;Go containers (and any other compile language) can be optimized even more. (much more 😄)&lt;br&gt;
Because their runtime is tied to them, you don't need something like Nodejs installed and you can drop compiler itself in the second stage and just use a binary executable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="c"&gt;# Copy go.mod and go.sum first, because of caching reasons.&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod go.sum ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go mod download
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./&lt;/span&gt;
&lt;span class="c"&gt;# Compile project&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux go build &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; main .

&lt;span class="c"&gt;# Use another clean image without Golang compiler.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/main .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["./main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqsvhsai9tb5pneo6lgv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqsvhsai9tb5pneo6lgv.png" alt="Optimizing Golang Container Image Size" width="565" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's right! we saved about 96% of our space!&lt;br&gt;
First result is without multistage technique,&lt;br&gt;
Second is using alpine-3.15 as production.&lt;br&gt;
Third is using gcr.io/distroless/static-debian11 that is the smallest image out there.&lt;/p&gt;
&lt;h2&gt;
  
  
  Including UI
&lt;/h2&gt;

&lt;p&gt;You can even add a UI to your Dockerfile in another stage!&lt;br&gt;
In this case, I have a Svelte SPA project beside my project (in ui folder) and I'm serving it from Go Backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;golang:1.18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; go.mod go.sum ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;go mod download
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nv"&gt;CGO_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;linux go build &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; main .

&lt;span class="c"&gt;# This stage convert svelte project to vanilla HTML, CSS, JS.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /ui&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ui .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/main .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=frontend /ui/public /ui&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["./main"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is a part of Blogo project.&lt;br&gt;
&lt;a href="https://github.com/arshamalh/blogo"&gt;https://github.com/arshamalh/blogo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you learned something from me here. 😃✌🏻&lt;br&gt;
Any suggestion or correction is welcome.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>typescript</category>
      <category>go</category>
    </item>
  </channel>
</rss>
