Pārlūkot izejas kodu

Merge branch 'master' into multiple

Louis Lam 1 gadu atpakaļ
vecāks
revīzija
f50c7cead8

+ 2 - 2
.github/workflows/ci.yml

@@ -14,8 +14,8 @@ jobs:
   ci:
     strategy:
       matrix:
-        os: [ubuntu-latest, windows-latest, macos-latest]
-        node: [20.x] # Can be changed
+        os: [ubuntu-latest, windows-latest, macos-latest, ARM64]
+        node: [18.17.1] # Can be changed
     runs-on: ${{ matrix.os }}
     steps:
       - name: Checkout Code

+ 26 - 19
README.md

@@ -34,12 +34,18 @@ View Video: https://youtu.be/AWAlOQeNpgU?t=48
 ## 🔧 How to Install
 
 Requirements:
-- [Docker CE](https://docs.docker.com/engine/install/) 20+ is recommended / Podman
-- (Docker only) [Docker Compose Plugin](https://docs.docker.com/compose/install/linux/)
+- [Docker](https://docs.docker.com/engine/install/) 20+ / Podman
 - (Podman only) podman-docker (Debian: `apt install podman-docker`)
 - OS:
-  - As long as you can run Docker CE / Podman, it should be fine, but:
-  - Debian/Raspbian Buster or lower is not supported, please upgrade to Bullseye or higher
+  - Major Linux distros that can run Docker/Podman such as:
+     - ✅ Ubuntu
+     - ✅ Debian (Bullseye or newer)
+     - ✅ Raspbian (Bullseye or newer)
+     - ✅ CentOS
+     - ✅ Fedora
+     - ✅ ArchLinux
+  - ❌ Debian/Raspbian Buster or lower is not supported
+  - ❌ Windows (Will be supported later)
 - Arch: armv7, arm64, amd64 (a.k.a x86_64)
 
 ### Basic
@@ -79,9 +85,6 @@ curl "https://dockge.kuma.pet/compose.yaml?port=5001&stacksPath=/opt/stacks" --o
 Interactive compose.yaml generator is available on: 
 https://dockge.kuma.pet
 
-You can also view compose.yaml here: 
-https://github.com/louislam/dockge/blob/master/compose.yaml
-
 ## How to Update
 
 ```bash
@@ -109,7 +112,7 @@ docker compose pull && docker compose up -d
 If you love this project, please consider giving it a ⭐.
 
 
-## 🗣️
+## 🗣️ Community and Contribution
 
 ### Bug Report
 https://github.com/louislam/dockge/issues
@@ -117,10 +120,13 @@ https://github.com/louislam/dockge/issues
 ### Ask for Help / Discussions
 https://github.com/louislam/dockge/discussions
 
-## Translation
-
+### Translation
 If you want to translate Dockge into your language, please read [Translation Guide](https://github.com/louislam/dockge/blob/master/frontend/src/lang/README.md)
 
+### Create a Pull Request
+
+Be sure to read the [guide](https://github.com/louislam/dockge/blob/master/CONTRIBUTING.md), as we don't accept all types of pull requests and don't want to waste your time.
+
 ## FAQ
 
 #### "Dockge"?
@@ -142,17 +148,18 @@ Yes, you can. However, you need to move your compose file into the stacks direct
 3. In Dockge, click the " Scan Stacks Folder" button in the top-right corner's dropdown menu
 4. Now you should see your stack in the list
 
-## More Ideas?
+#### Is Dockge a Portainer replcement?
+
+Yes or no. Portainer provides a lot of Docker features. While Dockge is currently only focusing on docker-compose with a better user interface and better user experience.
+
+If you want to manage your container with docker-compose only, the answer may be yes.
+
+If you still need to manage something like docker networks, signle containers, the answer may be no.
 
-- Stats
-- File manager
-- App store for yaml templates
-- Get app icons
-- Switch Docker context
-- Support Dockerfile and build
-- Support Docker swarm
+#### Can I install both Dockge and Portainer?
 
+Yes, you can.
 
-# Others
+## Others
 
 Dockge is built on top of [Compose V2](https://docs.docker.com/compose/migrate/). `compose.yaml`  also known as `docker-compose.yml`.

+ 3 - 3
backend/dockge-server.ts

@@ -156,9 +156,6 @@ export class DockgeServer {
             }
         }
 
-        // Create all the necessary directories
-        this.initDataDir();
-
         // Create express
         this.app = express();
 
@@ -275,6 +272,9 @@ export class DockgeServer {
      *
      */
     async serve() {
+        // Create all the necessary directories
+        this.initDataDir();
+
         // Connect to database
         try {
             await Database.init(this);

+ 1 - 1
backend/util-common.ts

@@ -203,7 +203,7 @@ export function getContainerTerminalName(container : string) {
 }
 
 export function getContainerExecTerminalName(stackName : string, container : string, index : number) {
-    return "container-exec-" + container + "-" + index;
+    return "container-exec-" + stackName + "-" + container + "-" + index;
 }
 
 export function copyYAMLComments(doc : Document, src : Document) {

+ 4 - 4
compose.yaml

@@ -13,10 +13,10 @@ services:
       # If you want to use private registries, you need to share the auth file with Dockge:
       # - /root/.docker/:/root/.docker
 
-      # Your stacks directory in the host (The paths inside container must be the same as the host)
-      # ⚠️⚠️ If you did it wrong, your data could end up be written into a wrong path.
-      # ✔️✔️✔️✔️ CORRECT: - /my-stacks:/my-stacks (Both paths match)
-      # ❌❌❌❌ WRONG: - /docker:/my-stacks (Both paths do not match)
+      # Stacks Directory
+      # ⚠️ READ IT CAREFULLY. If you did it wrong, your data could end up writing into a WRONG PATH.
+      # ⚠️ 1. FULL path only. No relative path (MUST)
+      # ⚠️ 2. Left Stacks Path === Right Stacks Path (MUST)
       - /opt/stacks:/opt/stacks
     environment:
       # Tell Dockge where is your stacks directory

+ 10 - 0
docker/BuildHealthCheck.Dockerfile

@@ -0,0 +1,10 @@
+############################################
+# Build in Golang
+############################################
+FROM golang:1.21.4-bookworm
+WORKDIR /app
+ARG TARGETPLATFORM
+COPY ./extra/healthcheck.go ./extra/healthcheck.go
+
+# Compile healthcheck.go
+RUN go build -x -o ./extra/healthcheck ./extra/healthcheck.go

+ 8 - 2
docker/Dockerfile

@@ -1,3 +1,8 @@
+############################################
+# Healthcheck Binary
+############################################
+FROM louislam/dockge:build-healthcheck AS build_healthcheck
+
 ############################################
 # Build
 ############################################
@@ -12,16 +17,17 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-l
 ############################################
 FROM louislam/dockge:base AS release
 WORKDIR /app
-COPY --chown=node:node  . .
+COPY --chown=node:node --from=build_healthcheck /app/extra/healthcheck /app/extra/healthcheck
 COPY --from=build /app/node_modules /app/node_modules
+COPY --chown=node:node  . .
 RUN mkdir ./data
 
 VOLUME /app/data
 EXPOSE 5001
+HEALTHCHECK --interval=60s --timeout=30s --start-period=60s --retries=5 CMD extra/healthcheck
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 CMD ["tsx", "./backend/index.ts"]
 
-
 ############################################
 # Mark as Nightly
 ############################################

+ 74 - 0
extra/healthcheck.go

@@ -0,0 +1,74 @@
+/*
+ * If changed, have to run `npm run build-docker-builder-go`.
+ * This script should be run after a period of time (180s), because the server may need some time to prepare.
+ */
+package main
+
+import (
+	"crypto/tls"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"strings"
+	"time"
+)
+
+func main() {
+	// Is K8S + "dockge" as the container name
+	// See https://github.com/louislam/uptime-kuma/pull/2083
+	isK8s := strings.HasPrefix(os.Getenv("DOCKGE_PORT"), "tcp://")
+
+	// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
+	http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
+		InsecureSkipVerify: true,
+	}
+
+	client := http.Client{
+		Timeout: 28 * time.Second,
+	}
+
+	sslKey := os.Getenv("DOCKGE_SSL_KEY")
+	sslCert := os.Getenv("DOCKGE_SSL_CERT")
+
+	hostname := os.Getenv("DOCKGE_HOST")
+	if len(hostname) == 0 {
+		hostname = "127.0.0.1"
+	}
+
+	port := ""
+	// DOCKGE_PORT is override by K8S unexpectedly,
+	if !isK8s {
+		port = os.Getenv("DOCKGE_PORT")
+	}
+	if len(port) == 0 {
+		port = "5001"
+	}
+
+	protocol := ""
+	if len(sslKey) != 0 && len(sslCert) != 0 {
+		protocol = "https"
+	} else {
+		protocol = "http"
+	}
+
+	url := protocol + "://" + hostname + ":" + port
+
+	log.Println("Checking " + url)
+	resp, err := client.Get(url)
+
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	defer resp.Body.Close()
+
+	_, err = ioutil.ReadAll(resp.Body)
+
+	if err != nil {
+		log.Fatalln(err)
+	}
+
+	log.Printf("Health Check OK [Res Code: %d]\n", resp.StatusCode)
+
+}

+ 84 - 0
extra/reset-password.ts

@@ -0,0 +1,84 @@
+import { Database } from "../backend/database";
+import { R } from "redbean-node";
+import readline from "readline";
+import { User } from "../backend/models/user";
+import { DockgeServer } from "../backend/dockge-server";
+import { log } from "../backend/log";
+
+console.log("== Dockge Reset Password Tool ==");
+
+const rl = readline.createInterface({
+    input: process.stdin,
+    output: process.stdout
+});
+
+export const main = async () => {
+    const server = new DockgeServer();
+
+    // Check if
+
+    console.log("Connecting the database");
+    try {
+        await Database.init(server);
+    } catch (e) {
+        if (e instanceof Error) {
+            log.error("server", "Failed to connect to your database: " + e.message);
+        }
+        process.exit(1);
+    }
+
+    try {
+        // No need to actually reset the password for testing, just make sure no connection problem. It is ok for now.
+        if (!process.env.TEST_BACKEND) {
+            const user = await R.findOne("user");
+            if (! user) {
+                throw new Error("user not found, have you installed?");
+            }
+
+            console.log("Found user: " + user.username);
+
+            while (true) {
+                let password = await question("New Password: ");
+                let confirmPassword = await question("Confirm New Password: ");
+
+                if (password === confirmPassword) {
+                    await User.resetPassword(user.id, password);
+
+                    // Reset all sessions by reset jwt secret
+                    await server.initJWTSecret();
+
+                    break;
+                } else {
+                    console.log("Passwords do not match, please try again.");
+                }
+            }
+            console.log("Password reset successfully.");
+        }
+    } catch (e) {
+        if (e instanceof Error) {
+            console.error("Error: " + e.message);
+        }
+    }
+
+    await Database.close();
+    rl.close();
+
+    console.log("Finished.");
+};
+
+/**
+ * Ask question of user
+ * @param question Question to ask
+ * @returns Users response
+ */
+function question(question : string) : Promise<string> {
+    return new Promise((resolve) => {
+        rl.question(question, (answer) => {
+            resolve(answer);
+        });
+    });
+}
+
+if (!process.env.TEST_BACKEND) {
+    main();
+}

+ 3 - 1
package.json

@@ -17,9 +17,11 @@
         "build:docker-base": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:base -f ./docker/Base.Dockerfile . --push",
         "build:docker": "node ./extra/env2arg.js docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:latest -t louislam/dockge:1 -t louislam/dockge:$VERSION --target release -f ./docker/Dockerfile . --push",
         "build:docker-nightly": "pnpm run build:frontend && docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:nightly --target nightly -f ./docker/Dockerfile . --push",
+        "build:healthcheck": "docker buildx build -f docker/BuildHealthCheck.Dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/dockge:build-healthcheck . --push",
         "start-docker": "docker run --rm -p 5001:5001 --name dockge louislam/dockge:latest",
         "mark-as-nightly": "tsx ./extra/mark-as-nightly.ts",
-        "reformat-changelog": "tsx ./extra/reformat-changelog.ts"
+        "reformat-changelog": "tsx ./extra/reformat-changelog.ts",
+        "reset-password": "tsx ./extra/reset-password.ts"
     },
     "dependencies": {
         "@homebridge/node-pty-prebuilt-multiarch": "~0.11.11",