{"id":134685,"date":"2021-04-30T19:17:26","date_gmt":"2021-04-30T18:17:26","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=go&#038;p=134685"},"modified":"2021-12-27T13:04:43","modified_gmt":"2021-12-27T12:04:43","slug":"how-to-use-docker-to-compile-go-from-goland","status":"publish","type":"go","link":"https:\/\/blog.jetbrains.com\/en\/go\/2021\/04\/30\/how-to-use-docker-to-compile-go-from-goland","title":{"rendered":"How to use Docker to compile and run Go code from GoLand"},"content":{"rendered":"\n<p>Up until now, when you wanted to test or run your shiny new code, you had only the local machine to do so.<\/p>\n\n\n\n<p>Many of our users have told us that they&#8217;d prefer to use Docker to run their code since that&#8217;s where they will ultimately test, build, and deploy the code with their CI\/CD pipeline.<\/p>\n\n\n\n<p>Today I&#8217;m happy to introduce to you our latest feature that allows you to seamlessly use Docker containers for your workflows from the comfort of your IDE.<\/p>\n\n\n\n<p>We call this feature &#8220;Run targets&#8221;, and it doesn&#8217;t extend to Docker support only. We currently support <em>Docker<\/em>, <em>WSL 2<\/em>, and <em>SSH remotes<\/em>.<\/p>\n\n\n\n<p>You may be asking: What are all these terms and technologies? Why is this interesting to me? If you&#8217;d like to learn more about these, <a href=\"https:\/\/blog.jetbrains.com\/en\/go\/2021\/04\/29\/what-are-run-targets-and-how-to-run-code-anywhere\">here&#8217;s an overview of this feature<\/a>, explaining it in more detail.<\/p>\n\n\n\n<p>In this article, I&#8217;ll focus on the Docker side of this feature.<\/p>\n\n\n\n<p>If you&#8217;d prefer a video version of this article, then please head to YouTube:<\/p>\n\n\n\n<p><iframe loading=\"lazy\" title=\"YouTube video player\" src=\"https:\/\/www.youtube.com\/embed\/iFgJmMV9Gxw\" allowfullscreen=\"allowfullscreen\" width=\"560\" height=\"315\" frameborder=\"0\"><\/iframe><\/p>\n\n\n\n<p>While Docker is not the only container technology, it&#8217;s by far the most popular one, which is why we&#8217;ll focus on this for now. If you&#8217;d like us to support other technologies, please let us know via our usual channels (see the end of this post).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-code\">The Code<\/h2>\n\n\n\n<p>Docker helps isolate the environment we run our code in, whether it&#8217;s tests or client-facing code.<\/p>\n\n\n\n<p>Let&#8217;s take a look at the following example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">package main\n\nimport (\n    &quot;fmt&quot;\n    &quot;log&quot;\n    &quot;net\/http&quot;\n    &quot;os&quot;\n    &quot;runtime&quot;\n)\n\nfunc homeHandler(w http.ResponseWriter, r *http.Request) {\n    myOS, myArch := runtime.GOOS, runtime.GOARCH\n    inContainer := &quot;inside&quot;\n    if _, err := os.Lstat(&quot;\/.dockerenv&quot;); err != nil &amp;&amp; os.IsNotExist(err) {\n        inContainer = &quot;outside&quot;\n    }\n\n    w.Header().Set(&quot;Content-Type&quot;, &quot;text\/plain&quot;)\n    w.WriteHeader(http.StatusOK)\n\n    _, _ = fmt.Fprintf(w, &quot;Hello, %s!\\n&quot;, r.UserAgent())\n    _, _ = fmt.Fprintf(w, &quot;I&#039;m running on %s\/%s.\\n&quot;, myOS, myArch)\n    _, _ = fmt.Fprintf(w, &quot;I&#039;m running %s of a container.\\n&quot;, inContainer)\n}\n\nfunc main() {\n    http.HandleFunc(&quot;\/&quot;, homeHandler)\n\n    err := http.ListenAndServe(&quot;:38000&quot;, nil)\n    if err != nil {\n        log.Fatalln(err)\n    }\n}<\/pre>\n\n\n\n<p>We are running a web server that listens on port <code>38000<\/code> and replies with some information about the running environment, such as the operating system and system architecture. It also performs a trivial check to see if it&#8217;s running inside a Docker container or not.<\/p>\n\n\n\n<p>When using a run configuration with default values, this sample application would launch on the local machine. If you are on Windows like I am, then the output would read as:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">Hello, Apache-HttpClient\/4.5.13 (Java\/11.0.10)!\nI&#039;m running on windows\/amd64.\nI&#039;m running outside a Docker container.<\/pre>\n\n\n<p><img decoding=\"async\" loading=\"lazy\" style=\"border: 1px solid #AAAAAA;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/04\/1-Run-a-regular-Run-Configuration-optimized.png\" data-gif-src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/GoLand\/Run Targets - Docker\/1 - Run a regular Run Configuration - optimized.gif\" alt=\"Run a regular Run Configuration\" width=\"750\" height=\"421\"><\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"enter-the-docker-container\">Enter the Docker Container<\/h2>\n\n\n\n<p>While running on the local machine is possible for such a simple application, what about a more complex application deployed in a Docker container? How could you replicate that environment?<\/p>\n\n\n\n<p>Here is where the IDE steps in and can automate everything using a Docker container via the Run Targets feature.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"using-a-container-from-a-registry\">Using a container from a Registry<\/h3>\n\n\n\n<p>To make use of this feature, we first need to create a new target.<\/p>\n\n\n\n<p>Head over to <code>Run | Manage Targets... | + | Docker<\/code> and select the Docker type from the list.<\/p>\n\n\n\n<p>You can select whether you want to use an existing container image or pull one from a repository.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"docker-pull-run-target\">Docker Pull Run Target<\/h3>\n\n\n\n<p>If you need to expose any ports or use any other flags for the container runtime, you can add them under Run options. By default, the IDE adds <code>\u2013rm<\/code> to remove the container after it stops, making cleanup easier.<\/p>\n\n\n\n<p>Clicking Next will pull the container and allow the IDE to do an introspection of the build\/run environment to detect where the <code>go<\/code> binary is, the <code>GOPATH<\/code>, and the Go version.<\/p>\n\n\n\n<p>Finally, you can configure the container directory in which the IDE will place the sources and adjust any previously auto-detected features.<\/p>\n\n\n<p><img decoding=\"async\" loading=\"lazy\" style=\"border: 1px solid #AAAAAA;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/04\/2-Create-Docker-Run-Target-optimized.png\" data-gif-src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/GoLand\/Run Targets - Docker\/2 - Create Docker Run Target - optimized.gif\" alt=\"Create a Docker Run Target\" width=\"750\" height=\"421\"><\/p>\n\n\n<p>There are two ways to use this feature once the target is available: either edit the existing run configuration or create a new one dedicated to running against the new target.<\/p>\n\n\n\n<p>Let&#8217;s change our existing run configuration and tell it to run our code using the Docker container.<\/p>\n\n\n\n<p>To do this, go to <code>Run | Edit Configurations...<\/code> and select the desired configuration.<\/p>\n\n\n\n<p>After changing the <code>Run on<\/code> field to match our newly created Target, we can then click <code>OK<\/code> and launch our configuration.<\/p>\n\n\n\n<p>The IDE will compile our binary on the local machine and run it via the Docker container.<\/p>\n\n\n\n<p><strong>Pro tip:<\/strong> If you want to build the binary inside the Docker container, you can enable <code>Build on remote target<\/code>.<\/p>\n\n\n<p><img decoding=\"async\" loading=\"lazy\" style=\"border: 1px solid #AAAAAA;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/04\/3-Change-Run-Configurations-Run-Target-optimized.png\" data-gif-src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/GoLand\/Run Targets - Docker\/3 - Change Run Configuration's Run Target - optimized.gif\" alt=\"Use a Run Target in a Run Configuration\" width=\"750\" height=\"421\"><\/p>\n\n\n<p>That&#8217;s it! Rerunning this configuration now works against our Docker container.<\/p>\n\n\n\n<p><strong>Pro tip:<\/strong> You can disable the Run after build option to allow the configuration to run only the compilation step.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"using-a-dockerfile\">Using a Dockerfile<\/h3>\n\n\n\n<p>We&#8217;ve seen this feature using a container that&#8217;s pulled from a registry. What if we don&#8217;t have a registry available?<\/p>\n\n\n\n<p>This is where the <code>Build<\/code> option from the Docker target type comes in.<\/p>\n\n\n\n<p>You&#8217;ll need to provide a Dockerfile that contains a Go installation.<br>Below, you can find an example of such a Dockerfile.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">FROM debian:buster\n\nRUN apt update &amp;&amp; \\\n    apt install -y curl\n\n# Work inside the \/tmp directory\nWORKDIR \/tmp\n\nRUN curl https:\/\/storage.googleapis.com\/golang\/go1.16.2.linux-amd64.tar.gz -o go.tar.gz &amp;&amp; \\\n    tar -zxf go.tar.gz &amp;&amp; \\\n    rm -rf go.tar.gz &amp;&amp; \\\n    mv go \/go\n\nENV GOPATH \/go\n\nENV PATH $PATH:\/go\/bin:$GOPATH\/bin\n\n# If you enable this, then gcc is needed to debug your app\nENV CGO_ENABLED 0\n\n# TODO: Add other dependencies and stuff here<\/pre>\n\n\n\n<p><em>Note:<\/em> I can&#8217;t stress enough that this Dockerfile <strong>should not<\/strong> be used to run <em>anything<\/em> in a production environment as it omits a lot of the best practices for how to configure a Docker container correctly. Go is not a scripting language, so it shouldn&#8217;t be included in any deployed image.<\/p>\n\n\n\n<p><strong>Note:<\/strong> Multi-stage Dockerfiles are supported as long as the final image contains the Go SDK and the GOPATH is correctly set. This is a requirement for the IDE to perform code compilation inside the container.<\/p>\n\n\n\n<p>Now, let&#8217;s create a new Docker Run Target, and this time select the <code>Build<\/code> option.<\/p>\n\n\n\n<p>We can specify additional arguments under the Optional section, such as the Image tag, Build options, Build arguments, and Run options. For now, I&#8217;ll include the port in the Run options to create a container that listens to the port that our application runs on.<\/p>\n\n\n\n<p>After a bit of introspection, we will have a similar screen to review\/customize any potential settings that we might want to, and then we are done.<\/p>\n\n\n\n<p>Let&#8217;s clone the run configuration and switch the <code>Run on<\/code> field to our newly created target.<\/p>\n\n\n<p><img decoding=\"async\" loading=\"lazy\" style=\"border: 1px solid #AAAAAA;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/04\/4-Configure-Docker-Build-Run-Target-optimized.png\" data-gif-src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/GoLand\/Run Targets - Docker\/4 - Configure Docker Build Run Target - optimized.gif\" alt=\"Create a Docker Build Run Target type\" width=\"750\" height=\"421\"><\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"debugging-using-a-docker-run-target\">Debugging using a Docker Run Target<\/h2>\n\n\n\n<p>Everything we&#8217;ve seen so far works with the debugger too.<\/p>\n\n\n\n<p>Let&#8217;s see this in action.<\/p>\n\n\n<p><img decoding=\"async\" loading=\"lazy\" style=\"border: 1px solid #AAAAAA;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/04\/5-Debug-using-a-Docker-Run-Target-optimized.png\" data-gif-src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/GoLand\/Run Targets - Docker\/5 - Debug using a Docker Run Target - optimized.gif\" alt=\"Debug a Go app in a Docker container using a Run Target\" width=\"750\" height=\"421\"><\/p>\n\n\n<h2 class=\"wp-block-heading\" id=\"running-test-and-benchmark\">Running tests and benchmarks<\/h2>\n\n\n\n<p>Running applications means that all our tests pass, and our benchmarks run well too.<\/p>\n\n\n\n<p>Go Test configuration types support Run targets too. Tests and benchmarks can run natively in the same environment as the application would by adjusting their target.<\/p>\n\n\n\n<p>For example, let&#8217;s create a new <code>Go Test<\/code> run configuration and set the <code>Run on<\/code> field to the same Docker container that we have for our application.<\/p>\n\n\n\n<p>As soon as we use the Run feature, it will start working in the same way as the Go Build configuration type, and our code will test inside the container.<\/p>\n\n\n\n<p>Running tests with coverage or profiling benchmarks is similar to this.<\/p>\n\n\n<p><img decoding=\"async\" loading=\"lazy\" style=\"border: 1px solid #AAAAAA;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/04\/6-Run-Test-with-Coverage-in-Docker-Run-Target-optimized.png\" data-gif-src=\"https:\/\/resources.jetbrains.com\/storage\/products\/blog\/wp-content\/uploads\/GoLand\/Run Targets - Docker\/6 - Run Test with Coverage in Docker Run Target - optimized.gif\" alt=\"Run a Test with Coverage in Docker using a Run Target\" width=\"750\" height=\"421\"><\/p>\n\n\n<p>And that&#8217;s it for today. We learned how to use Docker transparently to run our applications, tests, and benchmarks.<\/p>\n\n\n\n<p>Please keep in mind that this feature is still in its early days. We&#8217;d like to hear from you about any improvements we can make to transform this feature into another tool in your toolbelt.<\/p>\n\n\n\n<p>As always, you can reach out to us by commenting below this post, raise an issue on <a href=\"https:\/\/youtrack.jetbrains.com\/issues\/Go\" target=\"_blank\" rel=\"noopener\">our issue tracker<\/a>, ping us on <a href=\"https:\/\/app.slack.com\/client\/T029RQSE6\/C3FJ8M2PN\" target=\"_blank\" rel=\"noopener\">Gophers Slack in the #goland<\/a> channel, or via <a href=\"https:\/\/twitter.com\/GoLandIDE\" target=\"_blank\" rel=\"noopener\">@GoLandIDE on Twitter<\/a>.<\/p>\n","protected":false},"author":828,"featured_media":0,"comment_status":"closed","ping_status":"closed","template":"","categories":[808,4221,2347],"tags":[6412,3892,726,91,1038,6453],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/go\/134685"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/go"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/types\/go"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/users\/828"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/comments?post=134685"}],"version-history":[{"count":9,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/go\/134685\/revisions"}],"predecessor-version":[{"id":141261,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/go\/134685\/revisions\/141261"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/media?parent=134685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/categories?post=134685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/tags?post=134685"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/en\/wp-json\/wp\/v2\/cross-post-tag?post=134685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}