【问题标题】:How should I dockerize a CMS, such that MySQL works nice with git?我应该如何对 CMS 进行 dockerize,这样 MySQL 才能与 git 很好地配合使用?
【发布时间】:2020-07-07 15:20:16
【问题描述】:

我想将一个 MODX 应用程序 dockerize 用于开发并将其存储在 git 中(同样,用于开发。)有一个解决方案 here,但所有 MySQL 文件现在都是二进制文件,而且数据库关心它们的权限。我也愿意

  • 把mysql的所有数据都放在一个海量的二进制文件里,这样我就不用管权限了,可以放在LFS或者
  • 以某种方式在容器关闭时将数据库导出到 SQL 文件并在启动时导入,这样我就可以使用差异。

【问题讨论】:

  • 我强烈建议您不要尝试将数据库内容以任何形式存储在 Git 存储库中。可以将架构、一组固定装置或一组初始内容存储为 SQL 文件来为数据库播种,但您不应该在 Git 中存储实时数据库内容。
  • @bk2204 你还能如何将 CMS 放入 git 中?请至少在声称我不应该解决问题之前尝试理解问题。
  • 您将源代码放在 Git 而不是数据库中。一般来说,数据不属于修订控制系统。您还可以使用静态站点生成器,其全部内容都在 Git 中,并且没有数据库。
  • @bk2204 CMS 将自定义源代码、配置和其他所有内容存储在数据库中。我想将该代码和配置放入 Git,同时在运行时仍将其保存在数据库中,因为 CMS 需要这样做。静态网站生成器与我的问题有什么关系?
  • 您可以使用静态站点生成器代替 CMS,这是许多项目采用的方法。您尝试做的事情并不适合 Git,因此没有人会告诉您如何做会损坏且工作不佳的事情。

标签: mysql git docker content-management-system modx


【解决方案1】:

所以我实际上已经为您的问题实现了部分解决方案(虽然我仍在学习使用 docker,但这个潜在的解决方案封装了其他所有内容)。

我使用 MODx 作为我选择的 CMS,但是,理论上这也适用于其他 CMS。

在我的 git 工作流程中,我设置了一个预提交挂钩,用于将数据库转储为一系列 SQL 文件,在生产中实施时,这些文件代表 mysql 的输入以重新创建整个数据库。

下面例子中的一些代码和答案没有直接关系,另外值得注意的是,我个人在数据库的每个表中实现了一个final column,它实际上将不同行的数据分离到不同的分支中git repo(因为我选择的工作流程涉及 3 个并行分支,每个分支分别用于本地开发、暂存和生产)。

下面的示例代码是我的一个旧项目的预提交挂钩,我不再使用它,但相同的代码仍然在相对使用中(除了一些与本文无关的例外情况)。它远远超出了这个问题,因为它逐字逐句来自我的回购,但也许它可能会激发一些灵感。

在此示例中,您还将看到对“列表”的引用,这些列表是包含各种单独存储库和一些设置的文本文件,它们被内爆到 bash 关联数组中,这需要 bash 4.0 或更高版本。还有对“mysql-defaults”的引用,它是一个包含我的数据库凭据的文本文件,因此脚本可以不间断地运行。

#!/bin/bash

# Set repository and script variables
REPO_NAME='MODX';REPO_FOLDER='modx';REPO_KEY='modx';REPO_TYPE='MODX';

declare -a REPO_PREFIX_COUNTS=();

MODULES_STRING=$(cat /Users/cjholowatyj/Dev/modules-list | tr "\n" " ");MODULES_ARRAY=(${MODULES_STRING});# echo ${MODULES_ARRAY[1]};
PROJECTS_STRING=$(cat /Users/cjholowatyj/Dev/projects-list | tr "\n" " ");PROJECTS_ARRAY=(${PROJECTS_STRING});# echo ${PROJECTS_ARRAY[1]};
THEMES_STRING=$(cat /Users/cjholowatyj/Dev/themes-list | tr "\n" " ");THEMES_ARRAY=(${THEMES_STRING});# echo ${THEMES_ARRAY[1]};

alias mysql='/Applications/MAMP/Library/bin/mysql --defaults-file=.git/hooks/mysql-defaults';
alias dump='/Applications/MAMP/Library/bin/mysqldump --defaults-file=.git/hooks/mysql-defaults';
alias dump-compact='/Applications/MAMP/Library/bin/mysqldump --defaults-file=.git/hooks/mysql-defaults --no-create-info --skip-add-locks --skip-disable-keys --skip-comments --skip-extended-insert --compact';
shopt -s expand_aliases

# Print status message in terminal console
/bin/echo "Running ${REPO_NAME} Pre-Commits...";

# Switch to repository directory
# shellcheck disable=SC2164
cd "/Users/cjholowatyj/Dev/${REPO_FOLDER}/";

# Fetch database tables dedicated to this repository
mysql -N information_schema -e "select table_name from tables where table_schema = 'ka_local2019' and table_name like '${REPO_KEY}_%'" | tr '\n' ' ' > sql/${REPO_KEY}_tables.txt;
tablesExist=$(wc -c "sql/${REPO_KEY}_tables.txt" | awk '{print $1}')

# Reset pack_ sql files
if [[ -f sql/pack_structure.sql ]]; then rm sql/pack_structure.sql; fi
if [[ -f sql/pack_data.sql ]]; then rm sql/pack_data.sql; fi
touch sql/pack_structure.sql
touch sql/pack_data.sql

dump --add-drop-database --no-create-info --no-data --skip-comments --databases ka_local2019 >> sql/pack_structure.sql

# Process repository tables & data
if [[ ${tablesExist} -gt 0 ]]; then
  dump --no-data --skip-comments ka_local2019 --tables `cat sql/${REPO_KEY}_tables.txt` >> sql/pack_structure.sql
  dump-compact ka_local2019 --tables `cat sql/${REPO_KEY}_tables.txt` --where="flighter_key IS NULL" >> sql/pack_data.sql
  sed -i "" "s/AUTO_INCREMENT=[0-9]+[ ]//g" sql/pack_structure.sql
fi
dump-compact ka_local2019 --where="flighter_key='${REPO_KEY}'" >> sql/pack_data.sql
isLocalHead=$(grep -c cjholowatyj .git/HEAD);
if [[ ${isLocalHead} = 1 ]]; then
  dump-compact ka_local2019 --where="flighter_key='${REPO_KEY}-local'" >> sql/pack_data.sql
  sed -i "" "s/\.\[${REPO_KEY}-local]//g" sql/pack_data.sql
fi
isDevelopHead=$(grep -c develop .git/HEAD);
if [[ ${isDevelopHead} = 1 ]]; then
  dump-compact ka_local2019 --where="flighter_key='${REPO_KEY}-develop'" >> sql/pack_data.sql
  sed -i "" "s/\.\[${REPO_KEY}-develop]//g" sql/pack_data.sql
  sed -i "" "s/ka_local2019/ka_dev2019/g" sql/pack_structure.sql
  sed -i "" "s/ka_local2019/ka_dev2019/g" sql/pack_structure.sql
fi
isReleaseHead=$(grep -c release .git/HEAD);
if [[ ${isReleaseHead} = 1 ]]; then
  dump-compact ka_local2019 --where="flighter_key='${REPO_KEY}-release'" >> sql/pack_data.sql
  sed -i "" "s/\.\[${REPO_KEY}-release]//g" sql/pack_data.sql
  sed -i "" "s/ka_local2019/ka_rel2019/g" sql/pack_structure.sql
  sed -i "" "s/ka_local2019/ka_rel2019/g" sql/pack_structure.sql
fi

# Create master structure sql file for this repository (and delete it once again if it is empty)
awk '/./ { e=0 } /^$/ { e += 1 } e <= 1' < sql/pack_structure.sql > sql/${REPO_KEY}_structure.sql
structureExists=$(wc -c "sql/${REPO_KEY}_structure.sql" | awk '{print $1}')
if [[ ${structureExists} -eq 0 ]]; then rm sql/${REPO_KEY}_structure.sql; fi

# Create master sql data file in case the entire database needs to be rebuilt from scratch
awk '/./ { e=0 } /^$/ { e += 1 } e <= 1' < sql/pack_data.sql > sql/all_${REPO_KEY}_data.sql

# Commit global repository sql files
git add sql/all_${REPO_KEY}_data.sql
if [[ ${structureExists} -gt 0 ]]; then git add sql/${REPO_KEY}_structure.sql; fi

# Deleting any existing sql files to recreate them fresh below
if [[ -f sql/create_modx_data.sql ]]; then rm sql/create_modx_data.sql; fi
if [[ -f sql/create_flighter_data.sql ]]; then rm sql/create_flighter_data.sql; fi
for i in "${MODULES_ARRAY[@]}"
do
    if [[ -f sql/create_${i}_data.sql ]]; then rm sql/create_${i}_data.sql; fi
done
if [[ -f sql/create_${REPO_KEY}_data.sql ]]; then rm sql/create_${REPO_KEY}_data.sql; fi

# Parse global repository data and separate out data filed by table prefix
lastPrefix='';
lastTable='';
while IFS= read -r iLine;
do
    thisLine="${iLine}";
    thisPrefix=$(echo ${thisLine} | grep -oEi '^INSERT INTO `([0-9a-zA-Z]+)_' | cut -d ' ' -f 3 | cut -d '`' -f 2 | cut -d '_' -f 1);
    thisTable=$(echo ${thisLine} | grep -oEi '^INSERT INTO `([0-9a-zA-Z_]+)`' | cut -d ' ' -f 3 | cut -d '`' -f 2);
    if [[ $(echo -n ${thisPrefix} | wc -m) -gt 0 ]]; then
         if [[ -n "${REPO_PREFIX_COUNTS[$thisPrefix]}" ]]; then
              if [[ ${REPO_PREFIX_COUNTS[$thisPrefix]} -lt 1  ]]; then
                   if [[ -f sql/create_${thisPrefix}_data.sql ]]; then rm sql/create_${thisPrefix}_data.sql; fi
                   touch "sql/create_${thisPrefix}_data.sql";
              fi
              REPO_PREFIX_COUNTS[$thisPrefix]=0;
          fi
         REPO_PREFIX_COUNTS[$thisPrefix]+=1;
         echo "${thisLine}" >> sql/create_${thisPrefix}_data.sql;
         if [[ ${thisTable} != ${lastTable} ]]; then
             if [[ ${thisPrefix} != ${lastPrefix} ]]; then
                 if [[ -f sql/delete_${thisPrefix}_data.sql ]]; then rm sql/delete_${thisPrefix}_data.sql; fi
                 touch "sql/delete_${thisPrefix}_data.sql";
             fi
             if [[ $(echo -n ${thisTable} | wc -m) -gt 0 ]]; then
                 echo "DELETE FROM \`${thisTable}\` WHERE \`flighter_key\` LIKE '${REPO_KEY}%';" >> sql/delete_${thisPrefix}_data.sql
             fi
         fi
         # Add previous prefix sql file to git if lastPrefix isn't ''
         if [[ $(echo -n ${lastPrefix} | wc -m) -gt 0 ]]; then
             git add "sql/create_${lastPrefix}_data.sql";
             git add "sql/delete_${lastPrefix}_data.sql";
         fi
    fi
    lastPrefix=${thisPrefix};
    lastTable=${thisTable};
done < sql/all_${REPO_KEY}_data.sql
# Add previous prefix sql file to git for the final lastPrefix value
git add "sql/create_${lastPrefix}_data.sql";
git add "sql/delete_${lastPrefix}_data.sql";

# Clean up unused files
rm "sql/${REPO_KEY}_tables.txt";
rm "sql/pack_data.sql";
rm "sql/pack_structure.sql";

git add sql/;

值得注意的一些细微差别是... (1) 我的代码从每个表中删除了所有 auto_increment 游标,因为它们在 sql 文件中创建了许多不必要的更改,最终使提交变得更加复杂。 (2) 我的代码还去掉了数据库名称本身,因为在生产服务器上,我将指定将使用的数据库,它与我用于本地开发的数据库名称不同,我们没有想要数据去错地方。 (3) 此工作流程还将数据库结构和我提交给 git 的文件中的数据本身分开,如果您还没有意识到这一点,这可能会造成混淆。

另一方面,当在服务器上实现项目时,我也有代码可以直观地遍历所有 *.sql 文件并将它们一次导入到我的数据库中。出于安全原因,我不会分享确切的代码,但一般要点是...mysql mysql_database &lt; database_file.sql

【讨论】:

  • 这很棒。它对我没有帮助,因为我想在 Docker 中运行 MySQL,但我会记住的。
猜你喜欢
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-15
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多