我应该如何对 CMS 进行 docker 化,以便 MySQL 与 git 一起工作?

How should I dockerize a CMS, such that MySQL works nice with git?

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

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

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

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

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

下面的示例代码是我的一个旧项目的预提交挂钩,我不再使用它,但相同的代码仍在使用(除了一些与此无关的例外 post ).它远远超出了问题的范围,因为它是我的回购协议中的逐字记录,但也许它可能会激发一些灵感。

在此示例中,您还会看到对“列表”的引用,它们是包含各种个人存储库和一些设置的文本文件,它们被分解为 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 }')

# 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 }')
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) 我的代码从每个 table 中删除了所有 auto_increment 游标,因为它们在 [=41] 中创建了很多不必要的更改=] 文件,最终使提交变得更加复杂。 (2) 我的代码也删除了数据库名称本身,因为在生产服务器上,我将指定将要使用的数据库,它与我用于本地开发的数据库名称不同,我们不这样做希望数据去错地方。 (3) 此工作流还将数据库结构和我提交给 git 的文件中的数据本身分开,如果您还没有意识到这一点,这可能会造成混淆。

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