浏览代码

[Mysql] use python bootstrapper to start MYSQL container

FreddleSpl0it 3 月之前
父节点
当前提交
faf8fa8c2c

+ 1 - 0
.gitignore

@@ -53,6 +53,7 @@ data/conf/sogo/cron.creds
 data/conf/sogo/custom-fulllogo.svg
 data/conf/sogo/custom-shortlogo.svg
 data/conf/sogo/custom-fulllogo.png
+data/conf/mysql/my.cnf
 data/gitea/
 data/gogs/
 data/hooks/dovecot/*

+ 5 - 3
data/Dockerfiles/bootstrap/main.py

@@ -23,6 +23,8 @@ def main():
     from modules.BootstrapRspamd import Bootstrap
   elif container_name == "clamd-mailcow":
     from modules.BootstrapClamd import Bootstrap
+  elif container_name == "mysql-mailcow":
+    from modules.BootstrapMysql import Bootstrap
   else:
     print(f"No bootstrap handler for container: {container_name}", file=sys.stderr)
     sys.exit(1)
@@ -31,9 +33,9 @@ def main():
     container=container_name,
     db_config={
       "host": "localhost",
-      "user": os.getenv("DBUSER"),
-      "password": os.getenv("DBPASS"),
-      "database": os.getenv("DBNAME"),
+      "user": os.getenv("DBUSER") or os.getenv("MYSQL_USER"),
+      "password": os.getenv("DBPASS") or os.getenv("MYSQL_PASSWORD"),
+      "database": os.getenv("DBNAME") or os.getenv("MYSQL_DATABASE"),
       "unix_socket": "/var/run/mysqld/mysqld.sock",
       'connection_timeout': 2
     },

+ 80 - 0
data/Dockerfiles/bootstrap/modules/BootstrapMysql.py

@@ -0,0 +1,80 @@
+from jinja2 import Environment, FileSystemLoader
+from modules.BootstrapBase import BootstrapBase
+from pathlib import Path
+import os
+import sys
+import time
+import platform
+import subprocess
+
+class Bootstrap(BootstrapBase):
+  def bootstrap(self):
+    self.upgrade_mysql()
+
+    # Setup Jinja2 Environment and load vars
+    self.env = Environment(
+      loader=FileSystemLoader('./etc/mysql/conf.d/config_templates'),
+      keep_trailing_newline=True,
+      lstrip_blocks=True,
+      trim_blocks=True
+    )
+    extra_vars = {
+    }
+    self.env_vars = self.prepare_template_vars('/overwrites.json', extra_vars)
+
+    print("Set Timezone")
+    self.set_timezone()
+
+    print("Render config")
+    self.render_config("my.cnf.j2", "/etc/mysql/conf.d/my.cnf")
+
+  def upgrade_mysql(self, max_retries=5, wait_interval=3):
+    """
+    Runs mysql_upgrade in a controlled way using run_command.
+    Starts mysqld in background, upgrades, shuts down, then restarts in foreground.
+    """
+
+    dbuser = "root"
+    dbpass = os.getenv("MYSQL_ROOT_PASSWORD", "")
+    socket = "/var/run/mysqld/mysqld.sock"
+
+    print("Starting temporary mysqld for upgrade...")
+    temp_proc = subprocess.Popen([
+      "mysqld",
+      "--user=mysql",
+      "--skip-networking",
+      f"--socket={socket}"
+    ])
+
+    self.connect_mysql()
+
+    print("Running mysql_upgrade...")
+    retries = 0
+    while retries < max_retries:
+      result = self.run_command([
+        "mysql_upgrade",
+        "-u", dbuser,
+        f"-p{dbpass}",
+        f"--socket={socket}"
+      ], check=False)
+
+      if result.returncode == 0:
+        print("mysql_upgrade completed successfully.")
+        break
+      else:
+        print(f"mysql_upgrade failed (try {retries+1}/{max_retries})")
+        retries += 1
+        time.sleep(wait_interval)
+    else:
+      print("mysql_upgrade failed after all retries.")
+      temp_proc.terminate()
+      return False
+
+    print("Shutting down temporary mysqld...")
+    self.run_command([
+      "mariadb-admin",
+      "shutdown",
+      f"--socket={socket}",
+      "-u", dbuser,
+      f"-p{dbpass}"
+    ])

+ 28 - 0
data/Dockerfiles/mariadb/Dockerfile

@@ -0,0 +1,28 @@
+FROM mariadb:10.11
+
+LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
+
+
+RUN apt-get update && \
+  apt-get install -y --no-install-recommends \
+    python3 \
+    python3-pip \
+    gosu \
+  && apt-get clean \
+  && rm -rf /var/lib/apt/lists/*
+
+RUN pip install \
+  mysql-connector-python \
+  jinja2 \
+  redis \
+  dnspython
+
+
+COPY data/Dockerfiles/bootstrap /bootstrap
+COPY data/Dockerfiles/mariadb/docker-entrypoint.sh /docker-entrypoint.sh
+
+RUN chmod +x /docker-entrypoint.sh
+
+
+ENTRYPOINT ["/docker-entrypoint.sh"]
+CMD ["mysqld"]

+ 20 - 0
data/Dockerfiles/mariadb/docker-entrypoint.sh

@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Run hooks
+for file in /hooks/*; do
+  if [ -x "${file}" ]; then
+    echo "Running hook ${file}"
+    "${file}"
+  fi
+done
+
+python3 -u /bootstrap/main.py
+BOOTSTRAP_EXIT_CODE=$?
+
+if [ $BOOTSTRAP_EXIT_CODE -ne 0 ]; then
+  echo "Bootstrap failed with exit code $BOOTSTRAP_EXIT_CODE. Not starting MariaDB."
+  exit $BOOTSTRAP_EXIT_CODE
+fi
+
+echo "Bootstrap succeeded. Starting MariaDB..."
+exec gosu mysql "$@"

+ 0 - 0
data/conf/mysql/my.cnf → data/conf/mysql/config_templates/my.cnf.j2


+ 0 - 0
data/hooks/mariadb/.gitkeep


+ 4 - 2
docker-compose.yml

@@ -17,16 +17,18 @@ services:
             - unbound
 
     mysql-mailcow:
-      image: mariadb:10.11
+      image: ghcr.io/mailcow/mariadb:nightly-19052025
       depends_on:
         - unbound-mailcow
         - netfilter-mailcow
       stop_grace_period: 45s
       volumes:
+        - ./data/hooks/mariadb:/hooks:z
+        - ./data/conf/mysql/:/etc/mysql/conf.d/:z
         - mysql-vol-1:/var/lib/mysql/
         - mysql-socket-vol-1:/var/run/mysqld/
-        - ./data/conf/mysql/:/etc/mysql/conf.d/:ro,Z
       environment:
+        - CONTAINER_NAME=mysql-mailcow
         - TZ=${TZ}
         - MYSQL_ROOT_PASSWORD=${DBROOT}
         - MYSQL_DATABASE=${DBNAME}