From c1092e12c012938f4bf78302c46d4e0077fe12e2 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Thu, 3 Jun 2021 21:40:34 +0100 Subject: [PATCH 1/3] Attempt 1 --- Dockerfile | 32 ++++++++++++++++++-------------- entrypoint.sh | 15 +++++++++++++++ 2 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index e249559e87..807d151b79 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,26 +1,30 @@ - -# Build Stage +# build stage FROM node:lts-alpine as build-stage -LABEL Maintainer Alicia Sykes - -RUN apk update WORKDIR /app -COPY package.json ./ -COPY yarn.lock ./ -RUN yarn install +COPY package*.json ./ +RUN yarn install --frozen-lockfile COPY . . RUN yarn build -# Production Stage -ENV PORT 80 +# production stage +FROM alpine:3.11 + +ENV USER darkhttpd +ENV GROUP darkhttpd +ENV GID 911 +ENV UID 911 +ENV PORT 8080 -FROM nginx:1.15.7-alpine as production-stage +RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \ + apk add -U --no-cache su-exec darkhttpd -COPY --from=build-stage /app/dist /usr/share/nginx/html +COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/ +COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets +COPY entrypoint.sh /entrypoint.sh EXPOSE ${PORT} -VOLUME /usr/share/nginx/html/item-icons -CMD ["nginx", "-g", "daemon off;"] +VOLUME /www/assets +ENTRYPOINT ["/bin/sh", "/entrypoint.sh"] \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000000..45e2caa41a --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +# Ensure default assets are present. +while true; do echo n; done | cp -Ri /www/default-assets/* /www/assets/ &> /dev/null + +# Ensure compatibility with previous version (config.yml was in the root directory) +if [ -f "/www/config.yml" ]; then + yes n | cp -i /www/config.yml /www/assets/ &> /dev/null +fi + +# Install default config if no one is available. +yes n | cp -i /www/default-assets/config.yml.dist /www/assets/config.yml &> /dev/null + +chown -R $UID:$GID /www/assets +exec su-exec $UID:$GID darkhttpd /www/ --no-listing --port "$PORT" \ No newline at end of file From e53f8f9d8fe020c2d7bd362487b5f4983ab8f826 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Fri, 4 Jun 2021 19:57:43 +0100 Subject: [PATCH 2/3] Improved the Docker deployment process, plus switched to a new Apline image --- Dockerfile | 41 ++++++++++++++++------------------- package.json | 7 ++++-- server.js | 61 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 82 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index 807d151b79..4f55795660 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,27 @@ -# build stage -FROM node:lts-alpine as build-stage +FROM node:lts-alpine -WORKDIR /app +# Define some ENV Vars +ENV PORT 80 +ENV DIRECTORY /app +ENV IS_DOCKER true -COPY package*.json ./ -RUN yarn install --frozen-lockfile - -COPY . . -RUN yarn build +# Create and set the working directory +WORKDIR ${DIRECTORY} -# production stage -FROM alpine:3.11 +# Copy over both 'package.json' and 'package-lock.json' (if available) +COPY package*.json ./ -ENV USER darkhttpd -ENV GROUP darkhttpd -ENV GID 911 -ENV UID 911 -ENV PORT 8080 +# Install project dependencies +RUN yarn -RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \ - apk add -U --no-cache su-exec darkhttpd +# Copy over all project files and folders to the working directory +COPY . . -COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/ -COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets -COPY entrypoint.sh /entrypoint.sh +# Build initial app for production +RUN yarn build +# Expose given port EXPOSE ${PORT} -VOLUME /www/assets -ENTRYPOINT ["/bin/sh", "/entrypoint.sh"] \ No newline at end of file + +# Finally, run start command to serve up the built application +CMD [ "yarn", "build-and-start"] \ No newline at end of file diff --git a/package.json b/package.json index e0e1a4d30f..9eaf0a92ed 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,16 @@ "start": "node server", "dev": "vue-cli-service serve", "build": "vue-cli-service build", - "lint": "vue-cli-service lint --fix" + "lint": "vue-cli-service lint --fix", + "build-watch": "vue-cli-service build --watch", + "build-and-start": "npm-run-all --parallel build start" }, "dependencies": { "axios": "^0.21.1", "connect": "^3.7.0", "crypto-js": "^4.0.0", "highlight.js": "^11.0.0", + "npm-run-all": "^4.1.5", "prismjs": "^1.23.0", "register-service-worker": "^1.6.2", "remedial": "^1.0.8", @@ -70,4 +73,4 @@ "> 1%", "last 2 versions" ] -} +} \ No newline at end of file diff --git a/server.js b/server.js index f9b9b72d9c..d277fe538f 100644 --- a/server.js +++ b/server.js @@ -1,13 +1,68 @@ const connect = require('connect'); const serveStatic = require('serve-static'); -const port = process.env.PORT || 3002; +const util = require('util'); +const dns = require('dns'); +const os = require('os'); + +const port = process.env.PORT || 80; /* eslint no-console: 0 */ +const printWelcomeMessage = () => { + getLocalIp().then(({ address }) => { + const ip = address || 'localhost'; + console.log(overComplicatedMessage(ip, port)); + }); +} + +const getLocalIp = () => { + const dnsLookup = util.promisify(dns.lookup); + return dnsLookup(os.hostname()); +} + +const overComplicatedMessage = (ip, port) => { + let msg = ''; + const chars = { + RESET: '\x1b[0m', + CYAN: '\x1b[36m', + GREEN: '\x1b[32m', + BLUE: '\x1b[34m', + UNDERLINE: '\033[4m', + BOLD: '\033[1m', + BR: '\n', + }; + const stars = (count) => new Array(count).fill('*').join(''); + const line = (count) => new Array(count).fill('━').join(''); + const blanks = (count) => new Array(count).fill(' ').join(''); + if (process.env.IS_DOCKER) { + const containerId = process.env.HOSTNAME || undefined; + msg = `${chars.BLUE}${stars(91)}${chars.BR}${chars.RESET}` + + `${chars.CYAN}${chars.BOLD}Welcome to Dashy! 🚀${chars.RESET}${chars.BR}` + + `${chars.GREEN}Your new dashboard is now up and running ` + + `${containerId ? `in container ID ${containerId}` : 'with Docker'}${chars.BR}` + + `After updating your config file, run '${chars.UNDERLINE}docker exec -it ` + + `${containerId || '[container-id]'} yarn build` + + `${chars.RESET}${chars.GREEN}' to rebuild${chars.BR}` + + `${chars.BLUE}${stars(91)}${chars.BR}${chars.RESET}`; + } else { + msg = `${chars.GREEN}┏${line(75)}┓${chars.BR}` + + `┃ ${chars.CYAN}${chars.BOLD}Welcome to Dashy! 🚀${blanks(55)}${chars.GREEN}┃${chars.BR}` + + `┃ ${chars.CYAN}Your new dashboard is now up and running at ${chars.UNDERLINE}` + + `http://${ip}:${port}${chars.RESET}${blanks(20 - ip.length)}${chars.GREEN}┃${chars.BR}` + + `┃ ${chars.CYAN}After updating your config file, run '${chars.UNDERLINE}yarn build` + + `${chars.RESET}${chars.CYAN}' to rebuild the app${blanks(6)}${chars.GREEN}┃${chars.BR}` + + `┗${line(75)}┛${chars.BR}${chars.BR}`; + } + return msg; +} + try { connect() .use(serveStatic(`${__dirname}/dist`)) - .listen(port, () => console.log(`Boom, app is running on port ${port} 🚀`)); + .listen(port, () => { + try { printWelcomeMessage(port); } + catch (e) { console.log('Dashy is Starting...'); } + }); } catch (error) { - console.log('Something fucked up', error); + console.log('Sorry, an error occurred ', error); } From 35bf27ee367afcf0966dd517905d13ce6d09b4b4 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Fri, 4 Jun 2021 20:16:54 +0100 Subject: [PATCH 3/3] Adds license to package.json, updates Docker docs --- README.md | 9 +++++---- package.json | 1 + yarn.lock | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9cf2c0b91b..d5716caffd 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,14 @@ ### Deploying with Docker from Source 🛳️ - Get Code: `git clone git@github.com:Lissy93/dashy.git` and `cd dashy` -- Configuration: Fill in you're settings in `./public/conf.yml` -- Build: `docker build -t lissy93/dashy .` -- Start: `docker run -p 8080:80 --name my-dashboard lissy93/dashy` +- Configuration: Create a YAML file with your configuration +- Build: `docker build -t dashy .` +- Start: `docker run -p [port]:80 -v [/path/to/local/conf.yml]:/app/public/conf.yml --name [my-dashboard] dashy` ### Deploying from Docker Hub 🐳 - Get the Image: `docker pull lissy93/dashy` -- Start the Container: `docker run -d -p 8080:80 --name my-dashboard lissy93/dashy` +- Start the Container: `docker run -d -p 8080:80 /path/to/local/conf.yml:/app/public/conf.yml --name my-dashboard lissy93/dashy` + ### Developing 🧱 - Get Code: `git clone git@github.com:Lissy93/dashy.git` and `cd dashy` - Install dependencies: `yarn` diff --git a/package.json b/package.json index 9eaf0a92ed..40c4173dca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "panel", "version": "0.1.0", + "license": "MIT", "scripts": { "start": "node server", "dev": "vue-cli-service serve", diff --git a/yarn.lock b/yarn.lock index 8903156d18..6ce83a77dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2935,7 +2935,7 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -5532,6 +5532,16 @@ load-json-file@^2.0.0: pify "^2.0.0" strip-bom "^3.0.0" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + loader-fs-cache@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz#f08657646d607078be2f0a032f8bd69dd6f277d9" @@ -5777,6 +5787,11 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -6170,6 +6185,21 @@ normalize-url@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== +npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -6651,6 +6681,11 @@ picomodal@^3.0.0: resolved "https://registry.yarnpkg.com/picomodal/-/picomodal-3.0.0.tgz#facd30f4fbf34a809c1e04ea525f004f399c0b82" integrity sha1-+s0w9PvzSoCcHgTqUl8ATzmcC4I= +pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -7282,6 +7317,15 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + read-pkg@^5.1.1: version "5.2.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" @@ -8143,6 +8187,15 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string.prototype.padend@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.2.tgz#6858ca4f35c5268ebd5e8615e1327d55f59ee311" + integrity sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + string.prototype.trimend@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80"