TeamCity: миграция базы данных с HSQLDB на MySQL

Автор: | 07/12/2013

teamcity_logoБаза данных для TeamCity содержит информацию о результатах и истории сборок, историю изменений в VCS, список и настройки build-агентов, очередь сборок, аккаунты пользователей и их настройки.

Официальное руководство по TeamCity говорит однозначно:

> In short, do not EVER use internal HSQLDB database for production TeamCity instances.

Потому – выполним миграцию на MySQL.

Кроме того – мы хотим сохранить уже имеющиеся настройки.

На всякий случай – не забывайте делать полный бекап, подробности в статье TeamCity: резервное копирование сервера с помощью утилиты maintainDB.

Качаем драйвер подключения к серверу баз данных:

http://dev.mysql.com/downloads/connector/j/

Находим необходимый файл:

$ tar tf mysql-connector-java-5.1.27.tar.gz  | grep "mysql-connector-java-5.1.27-bin.jar"

Извлекаем только его:

$ tar xf mysql-connector-java-5.1.27.tar.gz mysql-connector-java-5.1.27/mysql-connector-java-5.1.27-bin.jar

Копируем файл в каталог рабочий каталог сервера TeamCIty.BuildServer/lib/jdbc/:

$ cp mysql-connector-java-5.1.27/mysql-connector-java-5.1.27-bin.jar ../.BuildServer/lib/jdbc/

Переходим к настройке MySQL:

$ mysql -u root -p

Создаём базу данных:

mysql> create database teamcity_db1 default charset utf8;

Назначаем права:

mysql> grant all privileges on teamcity_db1.* to 'teamcity'@'localhost' identified by 'password';

Выходим из консоли mysql-клиента, и переходим в каталог TeamCity:

$ cd ../.BuildServer/config/

Останавливаем сервер:

$ ./../../TeamCity/bin/runAll.sh stop
Using CATALINA_BASE:   ./..
Using CATALINA_HOME:   ./..
Using CATALINA_TMPDIR: ./../temp
Using JRE_HOME:        /usr/java/jdk1.6.0_45/jre
Using CLASSPATH:       ./../bin/bootstrap.jar:./../bin/tomcat-juli.jar
Stopping TeamCity build agent...
Java executable is found in '/usr/java/jdk1.6.0_45/jre'.
Starting TeamCity Build Agent Launcher...
Agent home directory is /home/teamcity/TeamCity/buildAgent
Received stop command from console.
Sending agent shutdown command to: http://localhost:9090
Shutdown command successfully sent. Agent will exit when idle.

Проверим:

$ ps ux | grep teamcity

Копируем файл шаблона настроек подключения к серверу MySQL:

$ cp database.mysql.properties.dist database.properties

Редактируем его, указываем свои настройки:

connectionUrl=jdbc:mysql://localhost:3306/teamcity_db1
connectionProperties.user=teamcity
connectionProperties.password=password

Запускаем сервер:

$ ./../../TeamCity/bin/runAll.sh start

Заходим на страницу сервера – и видим ошибку:

Could not connect to MySQL server.
SQL error when doing: Connecting to MySQL
SQL query: connect
SQL exception: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

Находим файл лога сервера:

$ find ~ -name "teamcity-server.log"
/home/teamcity/TeamCity/logs/teamcity-server.log
$ tail /home/teamcity/TeamCity/logs/teamcity-server.log
[2013-12-02 12:46:01,771]   INFO -  jetbrains.buildServer.STARTUP - Using external (MYSQL) database
[2013-12-02 12:46:01,772]   INFO -  jetbrains.buildServer.STARTUP - Current stage: Connecting to the database
[2013-12-02 12:46:03,159]  ERROR -  jetbrains.buildServer.STARTUP - Could not connect to MySQL server.
SQL error when doing: Connecting to MySQL
SQL query: connect
SQL exception: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
[2013-12-02 12:46:03,160]   INFO -  jetbrains.buildServer.STARTUP - Current stage: TeamCity server startup error
[2013-12-02 12:46:03,160]   INFO -  jetbrains.buildServer.STARTUP - Administrator login is required from web UI using authentication token: 1789441316873297174

Останавливаем сервер:

$ ./../../TeamCity/bin/runAll.sh stop

Проверяем – есть ли доступ к базе у указанного пользователя:

$ mysql -u teamcity -p
Enter password:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| teamcity_db1 |
+--------------------+
mysql> use teamcity_db1;
Database changed
mysql> show tables;
Empty set (0.00 sec)

Есть.

Но проблема оказалось  в другом – в настройках подключения TeamCIty указан адрес MySQL как localhost, в то время как сам MySQL слушает адрес:

$ netstat -ln|grep 3306
tcp 0 0 10.***.***.239:3306 0.0.0.0:* LISTEN

Можно изменить настройки в файле конфигурации сервера MySQL:

# cat /etc/my.cnf | grep bind
bind-address=10.***.***.239

А можно – в настройках подключения TeamCIty:

connectionUrl=jdbc:mysql://10.***.***.239:3306/teamcity_db1

Запускаем сервер:

$ ./../../TeamCity/bin/runAll.sh start

Опять ошибка:

TeamCity server startup error

Unexpected error during connecting to the database: Unexpected exception SQLException: SQL error when doing: Connecting to MySQL
SQL query: connect
SQL exception: null, message from server: “Host ‘thucydides’ is not allowed to connect to this MySQL server”

Т.к. мы подключаемся через внешний IP – то и права у пользователя должны быть с доступом с любого внешнего адреса.

Редактируем пользователя MySQL.

Смотрим текущие привилегии:

mysql> select host,user from user where user = "teamcity";
+-----------+----------+
| host | user |
+-----------+----------+
| localhost | teamcity |
+-----------+----------+
1 row in set (0.01 sec)

Изменяем поле host – вместо localhost ставим % – т.е. любой:

mysql> update user set host="%" where user="teamcity" and host="localhost";
Query OK, 1 row affected (0.01 sec)
mysql> select host,user from user where user = "teamcity";
+------+----------+
| host | user |
+------+----------+
| % | teamcity |
+------+----------+
mysql> flush privileges;
Query OK, 0 rows affected (0.11 sec)

Запускаем сервер TeamCity:

$ ./../../TeamCity/bin/runAll.sh start

teamcity_mysql_1

Теперь всё в порядке 🙂

Посмотрим лог:

$ tail /home/teamcity/TeamCity/logs/teamcity-server.log
[2013-12-02 13:12:53,475] INFO - jetbrains.buildServer.STARTUP - Internal HSQL database file (/home/teamcity/.BuildServer/system/buildserver.data) exists, version: 2.2.9
[2013-12-02 13:12:53,531] INFO - jetbrains.buildServer.STARTUP - Database connection URL: jdbc:mysql://10.249.140.239:3306/teamcity_db1
[2013-12-02 13:12:53,531] INFO - jetbrains.buildServer.STARTUP - Using database connection URL from the database properties file. The URL is: jdbc:mysql://10.249.140.239:3306/teamcity_db1
[2013-12-02 13:12:53,531] INFO - jetbrains.buildServer.STARTUP - Using external (MYSQL) database
[2013-12-02 13:12:53,531] INFO - jetbrains.buildServer.STARTUP - Current stage: Connecting to the database
[2013-12-02 13:12:54,908] INFO - jetbrains.buildServer.STARTUP - Connected to the database successfully
[2013-12-02 13:12:54,911] INFO - jetbrains.buildServer.STARTUP - Current stage: Checking the database
[2013-12-02 13:12:55,091] INFO - jetbrains.buildServer.STARTUP - Database contains no tables.
[2013-12-02 13:12:55,095] INFO - jetbrains.buildServer.STARTUP - Current stage: Database is empty or doesn't exist
[2013-12-02 13:12:55,095] INFO - jetbrains.buildServer.STARTUP - Administrator login is required from web UI using authentication token: 9011271320520862873

TeamCity: миграция базы данных с HSQLDB на MySQL

НЕ нажимаем Proceed!

Можно зайти в панель управления, введя ключ из лог-файла – authentication token: 9011271320520862873, но ничего особо ценного там нет – в файле лога информации больше.

Приступаем к миграции текущей базы данных HSQLDB в новую базу MySQL.

Важно:

The target database must be empty before the migration process (it must NOT contain any tables).

База должна быть полностью пустая.

Останавливаем TeamCity:

$ ./../../TeamCity/bin/runAll.sh stop

Копируем файл настроек подключения к MySQL (желательно, т.к. во время миграции оригинальный скрипт будет заменён):

$ cp database.properties database.MySQL.properties

И запускаем процесс миграции:

$ ./../../TeamCity/bin/maintainDB.sh migrate -S /home/teamcity/.BuildServer/config/database.hsqldb.properties.dist -T /home/teamcity/.BuildServer/config/database.MySQL.properties
...
Finishing
Restoring finished with warnings
Changing default database connection in TeamCity configuration:
Renaming old database.properties file to: database.properties.before.20131202.132229
Copying target database properties file
from: /home/teamcity/.BuildServer/config/database.MySQL.properties
to: /home/teamcity/.BuildServer/config/database.properties
Done.

Тут ключи:

-S (source) – исходный файл настроек подключения к базе данных. Т.к. ранее использовался HSQLDB – указываем его файл;
-T (target) – файл настроек MySQL, в базу которого будет выполнена миграция данных.

О скрипте maintainDB.sh можно почитать в той же статье – TeamCity: резервное копирование сервера с помощью утилиты maintainDB.

Стартуем сервер:

$ ./../../TeamCity/bin/runAll.sh start

Проверим процессы MySQL:

mysql> show full processlist;
+---------+----------+------------------+--------------+---------+------+-------+-----------------------+
| Id | User | Host | db | Command | Time | State | Info |
+---------+----------+------------------+--------------+---------+------+-------+-----------------------+
| 1671019 | teamcity | localhost | teamcity_db1 | Query | 0 | NULL | show full processlist |
| 1671027 | teamcity | thucydides:14495 | teamcity_db1 | Sleep | 307 | | NULL |
| 1671029 | teamcity | thucydides:14497 | teamcity_db1 | Sleep | 3 | | NULL |
| 1671030 | teamcity | thucydides:14498 | teamcity_db1 | Sleep | 306 | | NULL |
| 1671032 | teamcity | thucydides:14524 | teamcity_db1 | Sleep | 242 | | NULL |
| 1671033 | teamcity | thucydides:14562 | teamcity_db1 | Sleep | 251 | | NULL |
+---------+----------+------------------+--------------+---------+------+-------+-----------------------+

Готово.

После переключения на новую базу данных – сервер сообщит, что

110 tables in the MySQL database currently use MyISAM storage engine. To achieve better performance, switching to the InnoDB storage engine is recommended. For instructions on converting MyISAM tables to InnoDB, refer to the MySQL documentation. Make sure you read our recommendations for configuring MySQL.

teamcity_mysql_5

Решение описано в статье MySQL: конвертация всех таблиц в базе данных из MyISAM в InnoDB.