From 52c66ab108056451a78e51c5b77ce0b002b733f5 Mon Sep 17 00:00:00 2001 From: Matthew Baggett Date: Sat, 27 Jan 2024 05:39:18 +0100 Subject: [PATCH] Add mysql-proxy --- .github/workflows/mysql-proxy.yml | 66 +++++++++++++++ mysql-proxy/.gitignore | 1 + mysql-proxy/.hadolint.yaml | 3 + mysql-proxy/Dockerfile | 59 +++++++++++++ mysql-proxy/README.md | 136 ++++++++++++++++++++++++++++++ mysql-proxy/main.lua | 5 ++ 6 files changed, 270 insertions(+) create mode 100644 .github/workflows/mysql-proxy.yml create mode 100755 mysql-proxy/.gitignore create mode 100644 mysql-proxy/.hadolint.yaml create mode 100755 mysql-proxy/Dockerfile create mode 100755 mysql-proxy/README.md create mode 100755 mysql-proxy/main.lua diff --git a/.github/workflows/mysql-proxy.yml b/.github/workflows/mysql-proxy.yml new file mode 100644 index 0000000..bf2c0ed --- /dev/null +++ b/.github/workflows/mysql-proxy.yml @@ -0,0 +1,66 @@ +name: Build MySQL Proxy + +on: + push: + paths: + - '.github/workflows/mysql-proxy.yml' + - 'mysql-proxy/**' + pull_request: + branches: + - '!dependabot/**' + workflow_run: + workflows: + - Build PHP Flavours + branches: [ 'master', 'feature/**' ] + types: + - completed + workflow_dispatch: + +jobs: + mysql-proxy-build: + name: "Build MySQL Proxy" + runs-on: ubuntu-latest + steps: + + - name: "Setup: Setup QEMU" + uses: docker/setup-qemu-action@v2 + + - name: "Setup: Expose GitHub Runtime" + uses: crazy-max/ghaction-github-runtime@v3 + + - name: "Setup: Setup Docker Buildx" + uses: docker/setup-buildx-action@v2 + + - name: "Setup: Login to Docker Hub" + if: ${{ !env.ACT }} + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + + - name: "Setup: Login to GHCR" + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ secrets.GHCR_USERNAME }} + password: ${{ secrets.GHCR_PASSWORD }} + + - name: "Setup: Checkout Source" + uses: actions/checkout@v4 + with: + sparse-checkout: | + mysql-proxy + + - name: "Build: Build & Push Image" + uses: docker/build-push-action@v5 + with: + context: mysql-proxy + target: mysql-proxy + platforms: ${{ !env.ACT && 'linux/amd64,linux/arm64' || 'linux/amd64' }} + pull: true + push: true + tags: | + ${{ !env.ACT && 'benzine/mysql-proxy:latest' || '' }} + ${{ !env.ACT && 'ghcr.io/benzine-framework/mysql-proxy:latest' || 'ghcr.io/benzine-framework/mysql-proxy:devel' }} + cache-from: ${{ !env.ACT && 'type=gha' || 'type=local,src=.cache' }} + cache-to: ${{ !env.ACT && 'type=gha,mode=max' || 'type=local,dest=.cache' }} diff --git a/mysql-proxy/.gitignore b/mysql-proxy/.gitignore new file mode 100755 index 0000000..723ef36 --- /dev/null +++ b/mysql-proxy/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/mysql-proxy/.hadolint.yaml b/mysql-proxy/.hadolint.yaml new file mode 100644 index 0000000..5fe823f --- /dev/null +++ b/mysql-proxy/.hadolint.yaml @@ -0,0 +1,3 @@ +ignored: + - DL3005 + - DL3008 diff --git a/mysql-proxy/Dockerfile b/mysql-proxy/Dockerfile new file mode 100755 index 0000000..c1c5c9a --- /dev/null +++ b/mysql-proxy/Dockerfile @@ -0,0 +1,59 @@ +FROM benzine/marshall:latest AS mysql-proxy + +LABEL maintainer="Matthew Baggett " \ + org.label-schema.vcs-url="https://github.com/benzine-framework/docker" \ + org.opencontainers.image.source="https://github.com/benzine-framework/docker" + +ENV MYSQL_PROXY_VERSION 0.8.5 +ENV MYSQL_PROXY_TAR_NAME mysql-proxy-$MYSQL_PROXY_VERSION-linux-debian6.0-x86-64bit +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get upgrade -y ca-certificates tzdata && \ + apt-get -y install --no-install-recommends \ + wget \ + mysql-client \ + && \ + wget https://downloads.mysql.com/archives/get/p/21/file/$MYSQL_PROXY_TAR_NAME.tar.gz && \ + tar -xzvf $MYSQL_PROXY_TAR_NAME.tar.gz && \ + mv $MYSQL_PROXY_TAR_NAME /opt/mysql-proxy && \ + rm $MYSQL_PROXY_TAR_NAME.tar.gz && \ + DEBIAN_FRONTEND=noninteractive apt-get -y remove wget && \ + apt-get autoremove -yqq && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/ && \ + chown -R root:root /opt/mysql-proxy && \ + printf "#!/bin/bash\n\ +\n\ +exec /opt/mysql-proxy/bin/mysql-proxy \\\\\n\ +--keepalive \\\\\n\ +--log-level=error \\\\\n\ +--plugins=proxy \\\\\n\ +--proxy-address=\${PROXY_DB_HOST}:\${PROXY_DB_PORT} \\\\\n\ +--proxy-backend-addresses=\${REMOTE_DB_HOST}:\${REMOTE_DB_PORT} \\\\\n\ +--proxy-lua-script=/opt/mysql-proxy/conf/main.lua\n\ +" >> /usr/local/bin//entrypoint.sh && \ + chmod u+x /usr/local/bin/entrypoint.sh && \ + ln -s /usr/local/bin/docker-entrypoint.sh /entrypoint.sh # shortcut + +HEALTHCHECK --interval=5s --timeout=3s --start-period=5s --retries=3 \ + CMD mysqladmin ping -h 127.0.0.1 -p 3306 -u root || exit 1 + +ENTRYPOINT [ "entrypoint.sh" ] + +COPY main.lua /opt/mysql-proxy/conf/main.lua + +# For another derived image: + +# --help-all +# --proxy-backend-addresses=mysql:3306 +# --proxy-skip-profiling +# --proxy-backend-addresses=host:port +# --proxy-read-only-backend-addresses=host:port +# --keepalive +# --admin-username=User +# --admin-password=Password +# --log-level=crititcal +# The log level to use when outputting error messages. +# Messages with that level (or lower) are output. +# For example, message level also outputs message with info, warning, and error levels. diff --git a/mysql-proxy/README.md b/mysql-proxy/README.md new file mode 100755 index 0000000..9c8fb7a --- /dev/null +++ b/mysql-proxy/README.md @@ -0,0 +1,136 @@ +# MySQL Proxy + +# Usage with docker-compose + +without +``` +version: '2' + +services: + db: + image: mysql:8.0.0 + restart: always + ports: + - "3307:3306" #for external connection + volumes: + - ../mysql-data/db:/var/lib/mysql #mysql-data + environment: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: dbuser + MYSQL_USER: dbuser + MYSQL_PASSWORD: password +``` + +within +``` +version: '2' + +services: + mysql: + image: mysql:8.0.0 + restart: always + expose: + - "3306" #for service mysql-proxy + ports: + - "3307:3306" #for external connection + volumes: + - ../mysql-data/db:/var/lib/mysql #mysql-data + environment: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: dbuser + MYSQL_USER: dbuser + MYSQL_PASSWORD: password + db: + image: matthewbaggett/mysql-proxy + expose: + - "3306" #for service php + ports: + - "3308:3306" #for external connection + restart: always + volumes: + - ../mysql-proxy-conf:/opt/mysql-proxy/conf + environment: + PROXY_DB_PORT: 3306 + REMOTE_DB_HOST: mysql + REMOTE_DB_PORT: 3306 + LUA_SCRIPT: "/opt/mysql-proxy/conf/main.lua" + depends_on: + - mysql +``` + +# Query to stdout +For `docker-compose up` without `-d` (`../mysql-proxy/main.lua`) +``` +function read_query(packet) + if string.byte(packet) == proxy.COM_QUERY then + print(string.sub(packet, 2)) + end +end +``` + +# Query logging for mysql-proxy + +``` +... + volumes: + - ../mysql-proxy-conf:/opt/mysql-proxy/conf + - ../mysql-proxy-logs:/opt/mysql-proxy/logs + environment: + PROXY_DB_PORT: 3306 + REMOTE_DB_HOST: mysql + REMOTE_DB_PORT: 3306 + LUA_SCRIPT: "/opt/mysql-proxy/conf/log.lua" + LOG_FILE: "/opt/mysql-proxy/logs/mysql.log" +... +``` + +`/mysql-proxy-conf/log.lua` https://gist.github.com/simonw/1039751 +``` +local log_file = os.getenv("LOG_FILE") + +local fh = io.open(log_file, "a+") + +function read_query( packet ) + if string.byte(packet) == proxy.COM_QUERY then + local query = string.sub(packet, 2) + fh:write( string.format("%s %6d -- %s \n", + os.date('%Y-%m-%d %H:%M:%S'), + proxy.connection.server["thread_id"], + query)) + fh:flush() + end +end +``` +# thanks + +https://hub.docker.com/r/zwxajh/mysql-proxy +https://hub.docker.com/r/gediminaspuksmys/mysqlproxy/ + +# logrotate +The image can be expand with `logrotate` +Config file `/etc/logrotate.d/mysql-proxy` (approximate) + +``` +/opt/mysql-proxy/mysql.log { + weekly + missingok + rotate 35600 + compress + delaycompress + notifempty + create 666 root root + postrotate + /etc/init.d/mysql-proxy reload > /dev/null + endscript +} +``` + +# troubleshooting +If you can't create the chain `mysql` -> `mysql-proxy` -> `external client liten 0.0.0.0:3308` +check extends ports on the `mysql` service and/or add `expose` directly +``` + expose: + - "3306" #for service mysql-proxy +``` + +> note: Log send to file with delay (buffering mechanism). You can restart the container for get the log immediately. \ No newline at end of file diff --git a/mysql-proxy/main.lua b/mysql-proxy/main.lua new file mode 100755 index 0000000..c70c007 --- /dev/null +++ b/mysql-proxy/main.lua @@ -0,0 +1,5 @@ +function read_query(packet) +-- if string.byte(packet) == proxy.COM_QUERY then +-- print(string.sub(packet, 2)) +-- end +end