{"id":415877,"date":"2022-03-14T13:00:54","date_gmt":"2022-03-14T10:00:54","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/"},"modified":"2022-03-14T13:00:54","modified_gmt":"2022-03-14T10:00:54","slug":"how-to-use-docker-to-package-cli-applications-cloudsavvy-it","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/","title":{"rendered":"#How to Use Docker to Package CLI Applications \u2013 CloudSavvy IT"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a2dc15fd92e9\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #dd3333;color:#dd3333\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #dd3333;color:#dd3333\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a2dc15fd92e9\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#%E2%80%9CHow_to_Use_Docker_to_Package_CLI_Applications_%E2%80%93_CloudSavvy_IT%E2%80%9D\" >&#8220;How to Use Docker to Package CLI Applications \u2013 CloudSavvy IT&#8221;<\/a><ul class='ez-toc-list-level-2' ><li class='ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#Why_Use_Docker_for_CLI_Apps\" >Why Use Docker for CLI Apps?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#Creating_a_Docker_Image_for_a_CLI_App\" >Creating a Docker Image for a CLI App<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#Putting_It_Together\" >Putting It Together<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#Managing_Persistent_Data\" >Managing Persistent Data<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#Other_Possible_Challenges\" >Other Possible Challenges<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-docker-to-package-cli-applications-cloudsavvy-it\/#Summary\" >Summary<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n<h1><span class=\"ez-toc-section\" id=\"%E2%80%9CHow_to_Use_Docker_to_Package_CLI_Applications_%E2%80%93_CloudSavvy_IT%E2%80%9D\"><\/span>&#8220;How to Use Docker to Package CLI Applications \u2013 CloudSavvy IT&#8221;<span class=\"ez-toc-section-end\"><\/span><\/h1>\n<div id=\"article-content-area\">\n<img loading=\"lazy\" decoding=\"async\" class=\"type:primaryImage aligncenter size-full wp-image-14169\" data-pagespeed-lazy-srcset=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/993634a1.png?width=398&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1 400w, https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/993634a1.png?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1 1200w\" sizes=\"auto, 400w, 1200w\" data-pagespeed-lazy-src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/993634a1.png?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"\" width=\"1200\" height=\"675\" src=\"\/pagespeed_static\/1.JiBnMqyl6S.gif\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>Docker is a popular platform for packaging <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">app<\/a>s as self-contained distributable artifacts. It creates images that include everything you need to run a particular software, such as its source code, third-party package dependencies, and required environment characteristics.<\/p>\n<p>As Docker images can run anywhere Docker\u2019s installed, they\u2019re a viable format for distributing your CLI applications. The Docker ecosystem includes Docker Hub as an available-by-default public registry, giving you a complete tool chain for publishing, updating, and documenting your tools.<\/p>\n<p>Here\u2019s how you can use Docker to package CLI apps instead of traditional OS package managers and standalone binary downloads.<\/p>\n<h2 id=\"why-use-docker-for-cli-apps\"><span class=\"ez-toc-section\" id=\"Why_Use_Docker_for_CLI_Apps\"><\/span>Why Use Docker for CLI Apps?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Docker can make it quicker and easier for users to get your new utility installed. They get to <code>docker run your-app<\/code> instead of having to look for platform-specific installation instructions. There\u2019s no manual extraction of <code>tar<\/code> archives, copying into system folders, or <code>PATH<\/code> editing involved.<\/p>\n<p>Dockerized software also makes it easy for users to select different versions, perform updates, and initiate rollbacks. Each distinct release you create should get its own immutable tag that uniquely identifies its Docker image. Unlike regular package managers, users can easily run two versions of your software side-by-side by starting containers based on different image tags.<\/p>\n<p>Another benefit is the ease with which users can safely try out your app without making a long-term commitment to it. People can be hesitant to add new packages to their machines lest the software fails to fully clean up after itself when removed. Docker containers have their own private filesystem; removing a container leaves no trace of its existence on the host. This could encourage more users to give your app a go.<\/p>\n<p>One natural consequence of Dockerized distribution is the requirement that users already have Docker running on their machine. Nowadays many developers will be running it as a matter of course so it\u2019s a fairly safe choice to make. If you\u2019re concerned about locking out users who don\u2019t want to use Docker, you can still provide alternative options via your existing distribution channels.<\/p>\n<h2 id=\"creating-a-docker-image-for-a-cli-app\"><span class=\"ez-toc-section\" id=\"Creating_a_Docker_Image_for_a_CLI_App\"><\/span>Creating a Docker Image for a CLI App<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Docker images for CLI apps are little different to those used for any other type of software. The objective is to provide an image that\u2019s as lightweight as possible while still bundling everything your application needs to operate.<\/p>\n<p>It\u2019s usually best to start from a minimal base image that runs a streamlined operating system like Alpine. Add just the packages your software requires, such as its programming language, framework, and dependencies.<\/p>\n<p>Two vital Dockerfile instructions for CLI tools are <code>ENTRYPOINT<\/code> and <code>CMD<\/code>. Together these define the foreground process that will run when containers are started from your image. Most base images will default to launching a shell when the container starts. You should change this so it\u2019s your app that runs automatically, removing the need for users to manually execute it within the container.<\/p>\n<p>The <code>ENTRYPOINT<\/code> Dockerfile instruction defines the container\u2019s foreground process. Set this to your application\u2019s executable:<\/p>\n<pre>ENTRYPOINT [\"demo-app\"]<\/pre>\n<p>The <code>CMD<\/code> instruction works in tandem with <code>ENTRYPOINT<\/code>. It supplies default arguments for the command that\u2019s set in the <code>ENTRYPOINT<\/code>. Arguments that the user supplies when starting the container with <code>docker run<\/code> will override the <code>CMD<\/code> set in the Dockerfile.<\/p>\n<p>A good use for <code>CMD<\/code> is when you want to show some basic help or version information when users omit a specific command:<\/p>\n<pre>ENTRYPOINT [\"demo-app\"]&#13;\nCMD [\"--version\"]<\/pre>\n<p>Here are a few examples showing how these two instructions result in different commands being run when containers are created:<\/p>\n<pre># Starting a new container from the \"demo-app-image:latest\" image&#13;\n&#13;\n# Runs \"demo-app --version\"&#13;\ndocker run demo-app-image:latest&#13;\n&#13;\n# Runs \"demo-app demo --foo bar\"&#13;\ndocker run demo-app-image:latest demo --foo bar<\/pre>\n<p>Neither of the examples require the user to type the <code>demo-app<\/code> executable name. It\u2019s automatically used as the foreground process because it\u2019s the configured <code>ENTRYPOINT<\/code>. The command receives the arguments the user gave to <code>docker run<\/code> after the image name. When no arguments are supplied, the default <code>--version<\/code> is used.<\/p>\n<p>These two instructions are the fundamental building blocks of Docker images housing CLI tools. You want your application\u2019s main executable to be the default foreground process so users don\u2019t have to invoke it themselves.<\/p>\n<h2 id=\"putting-it-together\"><span class=\"ez-toc-section\" id=\"Putting_It_Together\"><\/span>Putting It Together<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Here\u2019s a Docker image that runs a simple Node.js application:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\">#<span class=\"sy0\">!\/<\/span>usr<span class=\"sy0\">\/<\/span>local<span class=\"sy0\">\/<\/span>bin<span class=\"sy0\">\/<\/span>node\nconsole.<span class=\"me1\">log<\/span><span class=\"br0\">(<\/span><span class=\"st0\">\"Hello World\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<pre>FROM node:16-alpine&#13;\nWORKDIR \/hello-world&#13;\n&#13;\nCOPY .\/ .&#13;\n&#13;\nRUN npm install&#13;\n&#13;\nENTRYPOINT [\"hello-world.js\"]<\/pre>\n<p>The Alpine-based variant of the Node base image is used to reduce your image\u2019s overall size. The application\u2019s source code is copied into the image\u2019s filesystem via the <code>COPY<\/code> instruction. The project\u2019s npm dependencies are installed and the <code>hello-world.js<\/code> script is set as the image\u2019s entrypoint.<\/p>\n<p>Build the image using <code>docker build<\/code>:<\/p>\n<pre>docker build -t demo-app-image:latest<\/pre>\n<p>Now you can run the image to see <code>Hello World<\/code> emitted to your terminal:<\/p>\n<pre>docker run demo-app-image:latest<\/pre>\n<p>At this point you\u2019re ready to push your image to Docker Hub or another registry where it can be downloaded by users. Anyone with access to the image will be able to start your software using the Docker CLI alone.<\/p>\n<h2 id=\"managing-persistent-data\"><span class=\"ez-toc-section\" id=\"Managing_Persistent_Data\"><\/span>Managing Persistent Data<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Dockerizing a CLI application does come with some challenges. The most prominent of these is how to handle data persistence. Data created within a container is lost when that container stops unless it\u2019s saved to an outside Docker volume.<\/p>\n<p>You should write data to clearly defined paths that users can mount volumes to. It\u2019s good practice to group all your persistent data under a single directory, such as <code>\/data<\/code>. Avoid using too many locations that require multiple volumes to be mounted. Your getting started guide should document the volumes your application needs so users are able to set up persistence when they create their container.<\/p>\n<pre># Run demo-app with a data volume mounted to \/data&#13;\ndocker run -v demo-app-data:\/data demo-app-image:latest<\/pre>\n<h2 id=\"other-possible-challenges\"><span class=\"ez-toc-section\" id=\"Other_Possible_Challenges\"><\/span>Other Possible Challenges<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The mounting issue reappears when your command needs to interact with files on the host\u2019s filesystem. Here\u2019s a simple example of a file upload tool:<\/p>\n<pre>docker run file-uploader cp example.txt demo-server:\/example.txt<\/pre>\n<p>This ends up looking for <code>example.txt<\/code> <em>within<\/em> the container. In this situation, users will need to <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/docs.docker.com\/storage\/bind-mounts\">bind mount<\/a> their working directory so its content is available to the container:<\/p>\n<pre>docker run -v $PWD:\/file-uploader file-uploader cp example.txt demo-server:\/example.txt<\/pre>\n<p>It\u2019s also important to think about how users will supply config values to your application. If you normally read from a config file, bear in mind users will need to mount one into each container they create. Offering alternative options such as command-line flags and environment variables can streamline the experience for simple use cases:<\/p>\n<pre># Setting the LOGGING_DRIVER environment variable in the container&#13;\ndocker run -e LOGGING_DRIVER=json demo-app-image:latest<\/pre>\n<p>One other challenge concerns interactive applications that require user input. Users need to pass the <code>-it<\/code> flag to <code>docker run<\/code> to enable interactive mode and allocate a pseudo-TTY:<\/p>\n<pre>docker run -it demo-app-image:latest<\/pre>\n<p>Users must remember to set these flags when necessary or your program won\u2019t be able to collect any input. You should document commands that need a TTY so users aren\u2019t caught out by unexpected errors.<\/p>\n<p>These sticking points mean Dockerized applications can become unwieldy if they\u2019re not specifically designed with containerization in mind. Users get the best experience when your commands are pure, requiring no filesystem interactions and minimal configuration. When this is possible, a simple <code>docker run image-name<\/code> fulfills the objective of no-friction installation and usage. You can still containerize more complex software but you\u2019re increasingly reliant on users having a good working knowledge of the Docker CLI and its concepts.<\/p>\n<h2 id=\"summary\"><span class=\"ez-toc-section\" id=\"Summary\"><\/span>Summary<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Docker\u2019s not just for cloud deployments and background services. It\u2019s also increasingly popular as a distribution mechanism for regular console applications. You can readily publish, consume, run, and maintain software using the single <code>docker<\/code> CLI that many software practitioners already use day-to-day.<\/p>\n<p>Offering a ready-to-use Docker image for your application gives users more choice. Newcomers can get started with a single command that sets up a preconfigured environment with all dependencies catered for. There\u2019s no risk of polluting their Docker host\u2019s filesystem or environment, preventing conflicts with other packages and guaranteeing the ability to revert to a clean slate if desired.<\/p>\n<p>Building a Docker image is usually no more involved than the routines you\u2019re already using to submit builds to different OS package managers. The most important considerations are to keep your image as small as possible and ensure the entrypoint and command are appropriate for your application. This will give users the best possible experience when using your Dockerized software.\n<\/p><\/div>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.cloudsavvyit.com\/15713\/how-to-use-docker-to-package-cli-applications\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;How to Use Docker to Package CLI Applications \u2013 CloudSavvy IT&#8221; Docker is a popular platform for packaging apps as self-contained distributable artifacts. It creates images that include everything you need to run a particular software, such as its source code, third-party package dependencies, and required environment characteristics. As Docker images can run anywhere Docker\u2019s&#8230;<\/p>\n","protected":false},"author":1,"featured_media":415878,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/993634a1.png","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-415877","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/415877","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=415877"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/415877\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/415878"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=415877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=415877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=415877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}