mirror of
https://github.com/pterodactyl/documentation.git
synced 2025-12-10 10:44:43 -06:00
1 line
19 KiB
JavaScript
1 line
19 KiB
JavaScript
(window.webpackJsonp=window.webpackJsonp||[]).push([[32],{288:function(e,t,a){"use strict";a.r(t);var s=a(15),n=Object(s.a)({},(function(){var e=this,t=e._self._c;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"creating-a-custom-docker-image"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-custom-docker-image"}},[e._v("#")]),e._v(" Creating a Custom Docker Image")]),e._v(" "),t("p"),t("div",{staticClass:"table-of-contents"},[t("ul",[t("li",[t("a",{attrs:{href:"#creating-the-dockerfile"}},[e._v("Creating the Dockerfile")])]),t("li",[t("a",{attrs:{href:"#installing-dependencies"}},[e._v("Installing Dependencies")])]),t("li",[t("a",{attrs:{href:"#creating-a-container-user"}},[e._v("Creating a Container User")])]),t("li",[t("a",{attrs:{href:"#work-directory-entrypoint"}},[e._v("Work Directory & Entrypoint")])]),t("li",[t("a",{attrs:{href:"#entrypoint-script"}},[e._v("Entrypoint Script")])]),t("li",[t("a",{attrs:{href:"#modifying-the-startup-command"}},[e._v("Modifying the Startup Command")])]),t("li",[t("a",{attrs:{href:"#run-the-command"}},[e._v("Run the Command")]),t("ul",[t("li",[t("a",{attrs:{href:"#note"}},[e._v("Note")])])])])])]),t("p"),e._v(" "),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),t("p",[e._v("This tutorial uses examples from our "),t("a",{attrs:{href:"https://github.com/pterodactyl/images/tree/java",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("core:java")]),t("OutboundLink")],1),e._v(" docker image,\nwhich can be found on GitHub. This tutorial also assumes some knowledge of "),t("a",{attrs:{href:"https://docker.io/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Docker"),t("OutboundLink")],1),e._v(", we suggest\nreading up if this all looks foreign to you.")])]),e._v(" "),t("h2",{attrs:{id:"creating-the-dockerfile"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#creating-the-dockerfile"}},[e._v("#")]),e._v(" Creating the Dockerfile")]),e._v(" "),t("p",[e._v("The most important part of this process is to create the "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("Dockerfile")]),t("OutboundLink")],1),e._v("\nthat will be used by the Daemon. Due to heavy restrictions on server containers, you must setup this file in a specific manner.")]),e._v(" "),t("p",[e._v("We try to make use of "),t("a",{attrs:{href:"https://alpinelinux.org",target:"_blank",rel:"noopener noreferrer"}},[e._v("Alpine Linux"),t("OutboundLink")],1),e._v(" as much as possible for our images in order to keep their size down.")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# ----------------------------------")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Pterodactyl Core Dockerfile")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Environment: Java")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Minimum Panel Version: 0.6.0")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# ----------------------------------")]),e._v("\nFROM openjdk:8-jdk-alpine\n\nMAINTAINER Pterodactyl Software, "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("<")]),e._v("support@pterodactyl.io"),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v(">")]),e._v("\n\nRUN apk "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("add")]),e._v(" --no-cache "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("--update")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("curl")]),e._v(" ca-certificates openssl "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("git")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("tar")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("bash")]),e._v(" sqlite fontconfig "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("\\")]),e._v("\n "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("&&")]),e._v(" adduser --disabled-password "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("--home")]),e._v(" /home/container container\n\n"),t("span",{pre:!0,attrs:{class:"token environment constant"}},[e._v("USER")]),e._v(" container\nENV "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t("span",{pre:!0,attrs:{class:"token environment constant"}},[e._v("USER")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("container "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t("span",{pre:!0,attrs:{class:"token environment constant"}},[e._v("HOME")])]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("/home/container\n\nWORKDIR /home/container\n\nCOPY ./entrypoint.sh /entrypoint.sh\n\nCMD "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"/bin/bash"')]),e._v(", "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"/entrypoint.sh"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n")])])]),t("p",[e._v("Lets walk through the "),t("code",[e._v("Dockerfile")]),e._v(" above. The first thing you'll notice is the "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#from",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("FROM")]),t("OutboundLink")],1),e._v(" declaration.")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("FROM openjdk:8-jdk-alpine\n")])])]),t("p",[e._v("In this case, we are using "),t("a",{attrs:{href:"https://github.com/docker-library/openjdk",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("openjdk:8-jdk-alpine")]),t("OutboundLink")],1),e._v(" which provides us with Java 8.")]),e._v(" "),t("h2",{attrs:{id:"installing-dependencies"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#installing-dependencies"}},[e._v("#")]),e._v(" Installing Dependencies")]),e._v(" "),t("p",[e._v("The next thing we do is install the dependencies we will need using Alpine's package manager: "),t("code",[e._v("apk")]),e._v(". You'll notice some\nspecific flags that keep the container small, including "),t("code",[e._v("--no-cache")]),e._v(", as well as everything being contained in a\nsingle "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#run",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("RUN")]),t("OutboundLink")],1),e._v(" block.")]),e._v(" "),t("h2",{attrs:{id:"creating-a-container-user"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#creating-a-container-user"}},[e._v("#")]),e._v(" Creating a Container User")]),e._v(" "),t("p",[e._v("Within this "),t("code",[e._v("RUN")]),e._v(" block, you'll notice the "),t("code",[e._v("useradd")]),e._v(" command.")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("adduser "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-D")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-h")]),e._v(" /home/container container\n")])])]),t("div",{staticClass:"custom-block warning"},[t("p",{staticClass:"custom-block-title"},[e._v("WARNING")]),e._v(" "),t("p",[e._v("All Pterodactyl containers must have a user named "),t("code",[e._v("container")]),e._v(", and the user home "),t("strong",[e._v("must")]),e._v(" be "),t("code",[e._v("/home/container")]),e._v(".")])]),e._v(" "),t("p",[e._v("After we create that user, we then define the default container "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#user",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("USER")]),t("OutboundLink")],1),e._v("\nas well as a few "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#env",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("ENV")]),t("OutboundLink")],1),e._v(" settings to be applied to things running\nwithin the container.")]),e._v(" "),t("h2",{attrs:{id:"work-directory-entrypoint"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#work-directory-entrypoint"}},[e._v("#")]),e._v(" Work Directory & Entrypoint")]),e._v(" "),t("p",[e._v("One of the last things we do is define a "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#workdir",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("WORKDIR")]),t("OutboundLink")],1),e._v(" which\nis where everything else will be executed. The "),t("code",[e._v("WORKDIR")]),e._v(" must be set the "),t("code",[e._v("/home/container")]),e._v(".")]),e._v(" "),t("p",[e._v("Finally, we need to copy our "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#entrypoint",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("ENTRYPOINT")]),t("OutboundLink")],1),e._v(" script into\nthe docker image root. This is done using "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#copy",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("COPY")]),t("OutboundLink")],1),e._v(", after which\nwe define the command to be used when the container is started using "),t("a",{attrs:{href:"https://docs.docker.com/engine/reference/builder/#cmd",target:"_blank",rel:"noopener noreferrer"}},[t("code",[e._v("CMD")]),t("OutboundLink")],1),e._v(".\nThe "),t("code",[e._v("CMD")]),e._v(" line should always point to the "),t("code",[e._v("entrypoint.sh")]),e._v(" file.")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[e._v("COPY ./entrypoint.sh /entrypoint.sh\nCMD "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("[")]),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"/bin/bash"')]),e._v(", "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"/entrypoint.sh"')]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("]")]),e._v("\n")])])]),t("h2",{attrs:{id:"entrypoint-script"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#entrypoint-script"}},[e._v("#")]),e._v(" Entrypoint Script")]),e._v(" "),t("p",[e._v("In order to complete this "),t("code",[e._v("Dockerfile")]),e._v(", we will need an "),t("code",[e._v("entrypoint.sh")]),e._v(" file which tells Docker how to run this\nspecific server type.")]),e._v(" "),t("p",[e._v("These entrypoint files are actually fairly abstracted, and the Daemon will pass in the start command as an environment\nvariable before processing it and then executing the command.")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token shebang important"}},[e._v("#!/bin/bash")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("cd")]),e._v(" /home/container\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Output Current Java Version")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("java")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-version")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("## only really needed to show what version is being used. Should be changed for different applications")]),e._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Replace Startup Variables")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e._v("MODIFIED_STARTUP")]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),t("span",{pre:!0,attrs:{class:"token variable"}},[t("span",{pre:!0,attrs:{class:"token variable"}},[e._v("`")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("eval")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("echo")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("$(")]),e._v("echo $"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("STARTUP"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sed")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-e")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v("'s/{{/${/g'")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-e")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v("'s/}}/}/g'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),t("span",{pre:!0,attrs:{class:"token variable"}},[e._v("`")])]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("echo")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('":/home/container$ '),t("span",{pre:!0,attrs:{class:"token variable"}},[e._v("${MODIFIED_STARTUP}")]),e._v('"')]),e._v("\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[e._v("# Run the Server")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token variable"}},[e._v("${MODIFIED_STARTUP}")]),e._v("\n")])])]),t("p",[e._v("The second command, "),t("code",[e._v("cd /home/container")]),e._v(", simply ensures we are in the correct directory when running the rest of the\ncommands. We then follow that up with "),t("code",[e._v("java -version")]),e._v(" to output this information to end-users, but that is not necessary.")]),e._v(" "),t("h2",{attrs:{id:"modifying-the-startup-command"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#modifying-the-startup-command"}},[e._v("#")]),e._v(" Modifying the Startup Command")]),e._v(" "),t("p",[e._v("The most significant part of this file is the "),t("code",[e._v("MODIFIED_STARTUP")]),e._v(" environment variable. What we are doing in this case\nis parsing the environment "),t("code",[e._v("STARTUP")]),e._v(" that is passed into the container by the Daemon. In most cases, this variable\nlooks something like the example below:")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e._v("STARTUP")]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),t("span",{pre:!0,attrs:{class:"token string"}},[e._v('"java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}"')]),e._v("\n")])])]),t("div",{pre:!0},[t("p",[e._v("You'll notice some placeholders there, specifically "),t("code",[e._v("{{SERVER_MEMORY}}")]),e._v(" and "),t("code",[e._v("{{SERVER_JARFILE}}")]),e._v(". These both refer to\nother environment variables being passed in, and they look something like the example below.")])]),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e._v("SERVER_MEMORY")]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),t("span",{pre:!0,attrs:{class:"token number"}},[e._v("1024")]),e._v("\n"),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e._v("SERVER_JARFILE")]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),e._v("server.jar\n")])])]),t("p",[e._v("There are a host of different environment variables, and they change depending on the specific service option\nconfiguration. However, that is not necessarily anything to worry about here.")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[e._v("MODIFIED_STARTUP")]),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("=")]),t("span",{pre:!0,attrs:{class:"token variable"}},[t("span",{pre:!0,attrs:{class:"token variable"}},[e._v("`")]),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("eval")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[e._v("echo")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("$(")]),e._v("echo $"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("STARTUP"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[e._v("|")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token function"}},[e._v("sed")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-e")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v("'s/{{/${/g'")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-e")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[e._v("'s/}}/}/g'")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v(")")]),t("span",{pre:!0,attrs:{class:"token variable"}},[e._v("`")])]),e._v("\n")])])]),t("div",{pre:!0},[t("p",[e._v("The command above simply evaluates the "),t("code",[e._v("STARTUP")]),e._v(" environment variable, and then replaces anything surrounded in\ncurly braces "),t("code",[e._v("{{EXAMPLE}}")]),e._v(" with a matching environment variable (such as "),t("code",[e._v("EXAMPLE")]),e._v("). Thus, our "),t("code",[e._v("STARTUP")]),e._v(" command:")])]),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[e._v("java")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-Xms128M")]),e._v(" -Xmx"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("SERVER_MEMORY"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("M "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-jar")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("{")]),e._v("SERVER_JARFILE"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[e._v("}")]),e._v("\n")])])]),t("p",[e._v("Becomes:")]),e._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[e._v("java")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-Xms128M")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-Xmx1024M")]),e._v(" "),t("span",{pre:!0,attrs:{class:"token parameter variable"}},[e._v("-jar")]),e._v(" server.jar\n")])])]),t("h2",{attrs:{id:"run-the-command"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#run-the-command"}},[e._v("#")]),e._v(" Run the Command")]),e._v(" "),t("p",[e._v("The last step is to run this modified startup command, which is done with the line "),t("code",[e._v("${MODIFIED_STARTUP}")]),e._v(".")]),e._v(" "),t("h3",{attrs:{id:"note"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#note"}},[e._v("#")]),e._v(" Note")]),e._v(" "),t("p",[e._v("Sometimes you may need to change the permissions of the "),t("code",[e._v("entrypoint.sh")]),e._v(" file, on linux you can do this by executing "),t("code",[e._v("chmod +x entrypoint.sh")]),e._v(" in the directory where the file is.")])])}),[],!1,null,null,null);t.default=n.exports}}]); |