{"id":1099,"date":"2024-07-29T17:45:49","date_gmt":"2024-07-29T17:45:49","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2024\/07\/29\/how-to-create-dockerfiles-with-genai\/"},"modified":"2024-07-29T17:45:49","modified_gmt":"2024-07-29T17:45:49","slug":"how-to-create-dockerfiles-with-genai","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2024\/07\/29\/how-to-create-dockerfiles-with-genai\/","title":{"rendered":"How to Create Dockerfiles with GenAI\u00a0"},"content":{"rendered":"<p><em>This ongoing <\/em><a href=\"https:\/\/www.docker.com\/blog\/tag\/genai-docker-labs\/\" target=\"_blank\" rel=\"noopener\"><em>Docker Labs GenAI series<\/em><\/a><em> will explore the exciting space of AI developer tools. At Docker, we believe there is a vast scope to explore, openly and without the hype. We will share our explorations and collaborate with the developer community in real time. Although developers have adopted autocomplete tooling like GitHub Copilot and use chat, there is significant potential for AI tools to assist with more specific tasks and interfaces throughout the entire software lifecycle. Therefore, our exploration will be broad. We will be releasing things as open source so you can play, explore, and hack with us, too.<\/em><\/p>\n<p>As we learn how to work more effectively with generative AI, one of the tasks we return to is Dockerfile generation. Because we can equip our AI assistants with tools, does this allow us to reframe the problem of content generation as an interaction between LLMs and tools?<\/p>\n<p>If you ask ChatGPT to write a <a href=\"https:\/\/docs.docker.com\/reference\/dockerfile\/\" target=\"_blank\" rel=\"noopener\">Dockerfile<\/a> for your project, it will initiate a conversation with you and ask you to extract some details from your project (Figure 1).<\/p>\n<p><strong>Figure 1:<\/strong> Asking ChatGPT for help writing a Dockerfile.<\/p>\n<p>However, we can also equip our assistant with a tool to extract this information from the project directly. Instead of asking the user, an assistant can ask for a tool instead.<\/p>\n<h2 class=\"wp-block-heading\">Using tools<\/h2>\n<p>Here\u2019s an alternative framing. Let\u2019s prompt the assistant with two high-level instructions whenever it is asked to create a Dockerfile.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n* First, analyze the project to determine how it should be built.<br \/>\n* Once the analysis is complete, create a Dockerfile to build that project.\n<\/div>\n<p>In addition to these new prompts, we will also supply the LLM with two function definitions.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n[{&#8220;name&#8221;: &#8220;analyze_project&#8221;,<br \/>\n &#8220;description&#8221;: &#8220;Analyze a project to determine how it should be built&#8221;},<br \/>\n {&#8220;name&#8221;: &#8220;write_files&#8221;,<br \/>\n  &#8220;description&#8221;: &#8220;write a set of files to my project&#8221;,<br \/>\n  &#8220;parameters&#8221;: {&#8230;}}]\n<\/div>\n<p>With these two functions, the assistant will have enough agency that it can write a Dockerfile directly to a user\u2019s project. Unfortunately, without best practices, the actual Dockerfile content is never very good.\u00a0<\/p>\n<p>Here\u2019s an example of the kind of Dockerfile that gets generated when the assistant knows the kind of project but not much else.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Use the official Node.js image from the Docker Hub<br \/>\nFROM node:14\n<p># Create and change to the app directory<br \/>\nWORKDIR \/usr\/src\/app<\/p>\n<p># Copy the package.json and package-lock.json files<br \/>\nCOPY package*.json .\/<\/p>\n<p># Install dependencies<br \/>\nRUN npm install<\/p>\n<p># Copy the rest of the application code<br \/>\nCOPY . .<\/p>\n<p># Expose the port your app runs on<br \/>\nEXPOSE 3000<\/p>\n<p># Define the command to run your app<br \/>\nCMD [&#8220;npm&#8221;, &#8220;start&#8221;]\n<\/p><\/div>\n<p>This example shows several standard Dockerfile authoring problems.<\/p>\n<p>Uses out of date base images.<\/p>\n<p>Does not employ multi-stage builds.<\/p>\n<p>Skips newer Docker features such as cache mounts.<\/p>\n<p>So, what can we do about this? Let\u2019s extract some best practices for authoring NPM project Dockerfiles.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nWrite Dockerfiles for NPM projects using three stages.  Do these three steps sequentially.<br \/>\n* the first node dependencies stage should be called &#8220;deps&#8221;<br \/>\n  and it should fetch the runtime dependencies using npm ci<br \/>\n  with the &#8211;omit=dev flag.<br \/>\n* The second Dockerfile stage should be called build  and it should be based on the deps stage.<br \/>\n  It should run npm ci and then npm build<br \/>\n* The third Dockerfile stage should select a base image<br \/>\n  that is recommended by Scout and use that in the FROM line.<br \/>\n  This stage should do then do three things.<br \/>\n\t1. it copies the node_modules directory from the deps stage.<br \/>\n    2. it copies the dist directory from the build stage.<br \/>\n    3. it then runs npm start\n<p>If you need to use a RUN statement containing npm ci always<br \/>\nadd the argument &#8211;mount=type=cache,target=\/root\/.npm to the RUN instruction.<br \/>\nThe &#8211;mount argument should be placed between the word RUN and the npm command.<br \/>\nThis will cache the npm packages in the docker build cache and speed up the build process.<br \/>\nAfter selecting a base image, get a recommended tag. This recommendation will change over time but start with what is recommended now.\n<\/p><\/div>\n<p>We\u2019ll include this content in any conversation occurring in the context of an NPM project. We\u2019ll also add a third function.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n[{&#8220;name&#8221;: &#8220;docker_scout_tag_recommendation&#8221;,<br \/>\n  &#8220;description&#8221;: &#8220;get a recommended tag&#8221;,<br \/>\n  &#8220;parameters&#8221;: {&#8230;}}]\n<\/div>\n<p>At the time of writing, here\u2019s the output from our assistant. In this example, the assistant is using the GPT-4 model, but we are seeing the same results with other local models.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Stage 1 &#8211; Downloading dependencies<br \/>\nFROM node:22-slim AS deps<br \/>\nWORKDIR \/usr\/src\/app<br \/>\nCOPY package*.json .\/<br \/>\nRUN &#8211;mount=type=cache,target=\/root\/.npm npm ci &#8211;omit=dev\n<p># Stage 2 &#8211; Building application<br \/>\nFROM deps AS build<br \/>\nRUN &#8211;mount=type=cache,target=\/root\/.npm npm ci &amp;&amp; npm build<\/p>\n<p># Stage 3 &#8211; Using a recommended base image from Scout<br \/>\nFROM node:22-slim<br \/>\nWORKDIR \/usr\/src\/app<br \/>\nCOPY &#8211;from=deps \/usr\/src\/app\/node_modules .\/node_modules<br \/>\nCOPY &#8211;from=build \/usr\/src\/app\/dist .\/dist<br \/>\nCMD [ &#8220;npm&#8221;, &#8220;start&#8221; ]\n<\/p><\/div>\n<p>This is a big improvement. The three inputs that underlie this improvement are listed below.<\/p>\n<p>The two top-level instructions that anchor the process our assistant should use:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n* First, analyze the project to determine how it should be built.<br \/>\n* Once the analysis is complete, create a Dockerfile to build that project.\n<\/div>\n<p>The Markdown content that summarizes our Docker specific best practices.<\/p>\n<p>The functions (analyze_project, write_files, and docker_scout_tag_recommendation).<\/p>\n<p>Distilling best practices is certainly not easy, but a little can go a long way.\u00a0Still, it is still hard to know whether this can be considered an improvement over just using code templates. Our continuing investigation centers around whether generative AI will help us to more easily adapt these models to new knowledge, new features, and new project types.<\/p>\n<h3 class=\"wp-block-heading\">Conversation loop<\/h3>\n<p>It\u2019s instructive to go through the actual messages passed between agents here. It\u2019s particularly interesting to look at the interplay between the Assistant and the Tool agents. Near the end of the exchange, there is an unexpected twist where the write_files tool complains that it was passed an invalid JSON file. In this case, the assistant actually did generate invalid JSON and the tool was right to complain. However, the assistant also responded to this error by fixing the JSON and calling the tool a second time! That was <em>unscripted<\/em>.<\/p>\n<p>Another interesting example of an unscripted moment is the last message from the assistant. The assistant correctly determines that the task is now complete and generates a summary of the work that was done and why.<\/p>\n<h2 class=\"wp-block-heading\">Transcript<\/h2>\n<p><strong>System:<\/strong><\/p>\n<p>You are an assistant who specializes in authoring Dockerfiles for projects. Since you are an expert and know about their project, be definitive about recommendations.<\/p>\n<p><strong>User:<\/strong><\/p>\n<p>First, analyze the project to determine how it should be built.<\/p>\n<p>Once the analysis is complete, create a Dockerfile to build that project.<\/p>\n<p><strong>Assistant:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n[{:function {:arguments &#8220;{}&#8221; :name &#8220;analyze_project&#8221;}}]\n<\/div>\n<p><strong>Tool (analyze_project):<\/strong><\/p>\n<p>This is an NPM project.<\/p>\n<p><strong>System:<\/strong><\/p>\n<p>Write Dockerfiles for NPM projects using three stages. Do these three steps sequentially \u2026<\/p>\n<p>\u2026<\/p>\n<p>\u2026 (system prompts excluded for brevity) ..<\/p>\n<p>\u2026<\/p>\n<p><strong>Assistant:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n[{:function {:arguments &#8220;{<br \/>\n  &#8220;repository&#8221;: &#8220;node&#8221;<br \/>\n}&#8221;<br \/>\n             :name &#8220;docker_scout_tag_recommendation&#8221;}}]\n<\/div>\n<p><strong>Tool (docker_scout_tag_recommendation):<\/strong><\/p>\n<p>22-slim<\/p>\n<p><strong>Assistant:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n[{:function {:arguments &#8220;{<br \/>\n  &#8220;files&#8221;: [<br \/>\n    {<br \/>\n      &#8220;path&#8221;: &#8220;Dockerfile&#8221;,<br \/>\n      &#8220;content&#8221;: `<br \/>\n# Stage 1 &#8211; the build process<br \/>\nFROM node:22-slim AS deps<br \/>\nWORKDIR \/usr\/src\/app<br \/>\nCOPY package*.json .\/<br \/>\nRUN &#8211;mount=type=cache,target=\/root\/.npm npm ci &#8211;omit=dev<br \/>\n# Stage 2 &#8211; the production environment<br \/>\nFROM deps AS build<br \/>\nRUN npm ci &amp;&amp; npm run build<br \/>\n# Stage 3 &#8211; the production environment<br \/>\nFROM node:22-slim<br \/>\nWORKDIR \/usr\/src\/app<br \/>\nCOPY &#8211;from=deps \/usr\/src\/app\/node_modules .\/node_modules<br \/>\nCOPY &#8211;from=build \/usr\/src\/app\/dist .\/dist<br \/>\nCMD [ &#8220;npm&#8221;, &#8220;start&#8221; ]`,<br \/>\n      &#8220;executable&#8221;: false<br \/>\n    }<br \/>\n  ]<br \/>\n}&#8221;<br \/>\n             :name &#8220;write_files&#8221;}<br \/>\n  :id &#8220;call_6VVCLiXcIBNyEGPQwftR7xEV&#8221;}]\n<\/div>\n<p><strong>Tool:<\/strong><\/p>\n<p>function call write_files failed call exited with non-zero code (1):\u00a0 call exited with non-zero code (1): #error {rn :cause Unexpected character (\u2018`\u2019)<\/p>\n<p><strong>Assistant:<\/strong><\/p>\n<p>I apologize for the error. Let me try that again.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n[{:function {:arguments &#8220;{<br \/>\n  &#8220;files&#8221;: [<br \/>\n    {<br \/>\n      &#8220;path&#8221;: &#8220;Dockerfile&#8221;,<br \/>\n      &#8220;content&#8221;: &#8220;FROM node:22-slim AS deps\\nWORKDIR \/usr\/src\/app\\nCOPY package*.json .\/\\nRUN &#8211;mount=type=cache,target=\/root\/.npm npm ci &#8211;omit=dev\\n\\nFROM deps AS build\\nRUN npm ci &amp;&amp; npm run build\\n\\nFROM node:22-slim\\nWORKDIR \/usr\/src\/app\\nCOPY &#8211;from=deps \/usr\/src\/app\/node_modules .\/node_modules\\nCOPY &#8211;from=build \/usr\/src\/app\/dist .\/dist\\nCMD [ \\&#8221;npm\\&#8221;, \\&#8221;start\\&#8221; ]&#8221;,<br \/>\n      &#8220;executable&#8221;: false<br \/>\n    }<br \/>\n  ]<br \/>\n}&#8221;<br \/>\n             :name &#8220;write_files&#8221;}}]\n<\/div>\n<p><strong>Tool (write_files):<\/strong><\/p>\n<p>wrote 1 files: Dockerfile<\/p>\n<p><strong>Assistant:<\/strong><\/p>\n<p>I have written the Dockerfile for your NPM project. You can find it in your project folder. This Dockerfile uses a multi-stage build process to efficiently build and run your application within a Docker container. The first stage fetches the runtime dependencies, the second stage builds the application, and the final stage runs the application. Please let me know if you need further assistance.<\/p>\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n<p>For a generative AI assistant to improve its ability to generate Dockerfile content, we have identified both tools and stack-specific best practice content as key enablers. Incorporating these elements into a generative AI based assistant can serve as an alternative to code templates. We continue to evaluate whether this approach allows us to more easily adapt to new project types.<\/p>\n<p>As always, feel free to follow along in our <a href=\"https:\/\/github.com\/docker\/labs-make-runbook\/tree\/main\/prompts\/dockerfiles\" target=\"_blank\" rel=\"noopener\">public repo<\/a> and reach out. Everything we\u2019ve discussed in this blog post is available for you to try on your own projects.<\/p>\n<p>For more on what we\u2019re doing at Docker, <a href=\"https:\/\/www.docker.com\/newsletter-subscription\/\" target=\"_blank\" rel=\"noopener\">subscribe to our newsletter.<\/a><\/p>\n<h2 class=\"wp-block-heading\">Learn more<\/h2>\n<p>Subscribe to the <a href=\"https:\/\/www.docker.com\/newsletter-subscription\/\" target=\"_blank\" rel=\"noopener\">Docker Newsletter<\/a>.<\/p>\n<p>Read the <a href=\"https:\/\/www.docker.com\/blog\/tag\/genai-docker-labs\/\" target=\"_blank\" rel=\"noopener\">Docker Labs GenAI series<\/a>.<\/p>\n<p>Get the latest release of <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\" target=\"_blank\" rel=\"noopener\">Docker Desktop<\/a>.<\/p>\n<p>Vote on what\u2019s next! Check out our<a href=\"https:\/\/github.com\/docker\/roadmap\" target=\"_blank\" rel=\"noopener\"> public roadmap<\/a>.<\/p>\n<p>Have questions? The <a href=\"https:\/\/www.docker.com\/community\/\" target=\"_blank\" rel=\"noopener\">Docker community is here to help<\/a>.<\/p>\n<p>New to Docker? <a href=\"https:\/\/docs.docker.com\/desktop\/\" target=\"_blank\" rel=\"noopener\">Get started<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>This ongoing Docker Labs GenAI series will explore the exciting space of AI developer tools. At Docker, we believe there [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-1099","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1099","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=1099"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1099\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=1099"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=1099"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=1099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}