What is the common practice to create db schema in Cloud Foundry? - database

I have been quested for a while for a best practice to initialize the relational database schema and pre-populated data.
There are a couple of ways to make it happen:
Install the cf-ex-phpmyadmin and import the data and schema thru it
Use the VMC cli tool to create a tunnel the service from this link
If using ruby or python, use the db migration command in the manifest.yml. However, it will be executed on each instance and every time the instance re-stages.
Which one is commonly used and most effective?

VMC is very old and is no longer supported. I'd be surprised if it even works against a Cloud Foundry installation that has been deployed within the last couple years. You should use the new cf CLI.
If you were to put the command in your manifest, you could avoid having it run on every instance if you had a conditional guard that would only run the migrations if $CF_INSTANCE_INDEX equals 0, however it's not always a great idea to run migrations in your start command, since there is a hard timeout on your start command, and you don't want migrations to be interrupted if they are long migrations.
A good suggestion I've heard [1] is that migrations should be handled as a separate part of your deploy process, either by cf ssh or running them locally, pointed at the URL and credentials of your database service instance.
[1] credit to Travis Grathwell for this suggestion.

Related

How to solve liquibase waiting for changelog lock problem in several pods in OpenShift cluster?

We are supporting several microservices written in Java using Spring Boot and deployed in OpenShift. Some microservices communicate with databases. We often run a single microservice in multiple pods in a single deployment. When each microservice starts, it starts liquibase, which tries to update the database. The problem is that sometimes one pod fails while waiting for the changelog lock.
When this happens in our production OpenShift cluster, we expect other pods to fail while restarting because of the same problem with changelog lock issue. So, in the worst case scenario, all pods will wait for the lock to be lifted.
We want liquidbase to automatically prepare our database schemas when each pod is starting.
Is it good to store this logic in every microservice? How can we automatically solve the problem when the liquidbase changelog lock problem appears? Do we need to put the database preparation logic in a separate deployment?
So maybe I should paraphrase my question. What is the best way to run db migration in term of microservice architecture? Maybe we should not use db migration in each pod? Maybe it is better to do it with separate deployment or do it with some extra Jenkins job not in OpenShift at all?
We're running liquibase migrations as an init-container in Kubernetes. The problem with running Liquibase in micro-services is that Kubernetes will terminate the pod if the readiness probe is not successful before the configured timeout. In our case this happened sometimes during large DB migrations, which could take a few minutes to complete. Kubernetes will terminate the pod, leaving DATABASECHANGELOGLOCK in a locked state. With init-containers you will not have this problem. See https://www.liquibase.org/blog/using-liquibase-in-kubernetes for a detailed explanation.
UPDATE
Please take a look at this Liquibase extension, which replaces the StandardLockService, by using database locks: https://github.com/blagerweij/liquibase-sessionlock
This extension uses MySQL or Postgres user lock statements, which are automatically released when the database connection is closed (e.g. when the container is stopped unexpectedly). The only thing required to use the extension is to add a dependency to the library. Liquibase will automatically detect the improved LockService.
I'm not the author of the library, but I stumbled upon the library when I was searching for a solution. I helped the author by releasing the library to Maven central. Currently supports MySQL and PostgreSQL, but should be fairly easy to support other RDBMS.
When Liquibase kicks in during the spring-boot app deployment, it performs (on a very high level) the following steps:
lock the database (create a record in databasechangeloglock)
execute changeLogs;
remove database lock;
So if you interrupt application deployment while Liquibase is between steps 1 and 3, then your database will remain locked. So when you'll try to redeploy your app, Liquibase will fail, because it will treat your database as locked.
So you have to unlock the database before deploying the app again.
There are two options that I'm aware of:
Clear databasechangeloglock table or set locked to false. Which is DELETE FROM databasechangeloglock or UPDATE databasechangeloglock SET locked=0
Execute liquibase releaseLocks command. You can find documentation about it here and here.
We managed to solve this in my company by following also the same approach Liquibase suggests with Init Containers, but instead of using a new container and run the Liquibase migration via Liquibase CLI, we are reusing the existing Spring Boot service setup but just executing the Liquibase logic. We have created an alternative main class that can be used in an entrypoint to populate the database using Liquibase.
The InitContainerApplication class brings the minimal configuration required to start the application and set up Liquibase.
Typical usage:
entrypoint: "java -cp /app/extras/*:/app/WEB-INF/classes:/app/WEB-INF/lib/* com.backbase.buildingblocks.auxiliaryconfig.InitContainerApplication"
Here the class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.context.ApplicationContext;
#SpringBootConfiguration
#ImportAutoConfiguration(InitContainerAutoConfigurationSelector.class)
public class InitContainerApplication implements ApplicationRunner {
#Autowired
private ApplicationContext appContext;
public static void main(String[] args) {
SpringApplication.run(InitContainerApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
SpringApplication.exit(appContext, () -> 0);
}
}
Here is the use as an Init Container:
spec:
initContainers:
- name: init-liquibase
command: ['java']
args: ['-cp', '/app/extras/*:/app/WEB-INF/classes:/app/WEB-INF/lib/*',
'com.backbase.buildingblocks.auxiliaryconfig.InitContainerApplication']
Finally we solved this problem in another project by removing liquibase migration at microservice start time. Now separate Jenkins job apply the migration and separate Jenkins job deploy and start microservice after migration apply. So now microservice itself doesn’t apply database update
I encountered this issue when one of the Java applications I manage abruptly shut down.
The logs were displaying the error below when the application tries to start:
waiting to acquire changelock
Here's how I solved it
I fixed this issue by:
Stopping the application
Deleting the databasechangelog and databasechangelog.lock files in the database connected to the application.
Restarting the application
In my case the application was connected to 2 databases. I had to delete the databasechangelog and databasechangelog.lock files in the both databases and then restarted the application. The both database databasechangelog and databasechangelog.lock files have to be at sync.
After this the application was able to acquire changelock file.

keycloak external database schema

I'm starting to configure Keycloak to run on production environment and I need to use a database in order to run more than one instance with a single configuration repository. I'm using Oracle as SGBD.
But I didn't find the scripts to create the database in the Keycloak's git.
Does anyone knows where can I find them?
You don't need to specifically run a separate set of SQL files. Keycloak will run it for you on first startup.
A bit of advice as it's not really obvious at first - you'll either need to remove and install the default Keycloak data source (KeycloakDS) or manually modify the standalone.xml to point to the setup you want. It took me a little bit to figure out the order that I needed to do things.

Can I use environment-specific variables in EF manual migrations?

Background
My project is using Entity Framework
Migrations are being deployed via OctopusDeploy by using the migrate.exe executable
Problem / Goal
I need to script a set of permissions to the database for an account on each system, e.g.
When deployed to dev, account1 must be granted datareader/datawriter access
When deployed to test, account2 must be granted datareader/datawriter access.
etc.
I'd like to use the same system for this that we're using so far (manual code-based migrations). If possible, I'd like to script the permission grants for a database and run them as part of our migrate.exe execution on deployment.
However, because I'll only have one "migration" that applies these permissions, I don't know to ensure I apply the right permissions to the right user in each environment.
Questions
Is there a recommended way to know or apply which environment the migrations are a part of when running migrate.exe so that I can run it against all environments without issue?
Can I pass in some sort of variable to migrate.exe which I can then use in my migrations?
Is there something wrong in my premise / assumptions when approaching this?

Command line to initialize SonarQube database?

I'm trying to automate sonarqube installation.
One (small) issue I'm running into is after installation during first access, as sonarqube is initializing the db schema, we run into timeouts.
I'd like to know if there's a script/command to initialize the db (create tables and all) from the bash?
I've been digging on the internet and couldn't find an answer to that.
Thanks!
I'd like to complete answers from Seb and Jeroen.
Schema is indeed created programmatically by SonarQube during startup. This step can't be executed independently in a script. Just start server. Instead of parsing logs, I suggest to call the web service GET http:///api/system/status (see documentation at http://nemo.sonarqube.org/api_documentation/api/system/status) to know when database is fully initialized.
Database upgrade when installing a new release can also be triggered through the web service POST http:///api/system/migrate_db (see http://nemo.sonarqube.org/api_documentation/api/system/migrate_db).
Database initialization is built-in SonarQube and can not be run independently of starting SonarQube.
As suggested by #jeroen, you can indeed analyze the sonar.log file and wait for the web[o.s.s.a.TomcatAccessLog] Web server is started line.
You can build in a wait loop and/or analyze the SonarQube log file during startup.

magento: database synchronization between production, staging & development

I've been reading up today on database synchronization in Magento.
One thing I am currently struggling with is what needs to be synced during development and during uploads to production. Now assuming that a batch of changes will consist of changes to the DB and code alike, below would be my understanding of a model workflow (I do not currently use a 'stage' server so that is bypassed in this example):
Sync dev DB from production DB
Checkout working copy of code to dev machine
Make changes and test them on dev server
Accept changes and commit them to svn repository
Touch Maintenance.flag on production server and prepare for upgrades (this altogether eliminates sync issues from users interacting with live data that is about to change right?)
Merge branches to trunk and deploy repository to production server
Sync dev DB back to production DB and test changes
So items # 1 & 7 I don't fully understand when working with Magento:
What needs to be synced and what doesn't?
It seems ridiculous to sync order and customer info to me so I wouldn't do it.
I would want product schema and data synced though obviously, and any admin changes, module changes, etc. How to handle that?
What about HOW to sync? (MySql dumps, import/export, etc)
Currently I'm using Navicat 10 Premium which has structure and data sync features (I haven't experimented yet but they look like a huge help)
So I don't necessarily need specifics here (but they would help). More or less I want to know what works for you and how happy you are with that system.
if you are using CE version then:
ditch svn and use GIT :)
never sync a database , prepare your database upgrades as extension upgrade files
have 3 sites dev, stage, live
live database is copied over to stage and dev when needed
make all your admin changes from live and just copy the whole database down the line
this way you never have to sync a database + if you do all config changes via extension upgrade scripts you can cold boot your magento to a new database structure wherever you want without loosing data structure
I use phpunit to build a dev db. I wrote a short script which dumps xml data from the live database and I used it table-by-table, munging anything sensitive and deleting what I didn't need. The schema for my dev database never changes and never gets rebuilt. Only the data gets dropped and recreated each phpunit run.
May not be the right solution for everyone because it's never going to be good for syncing dev up to stage/production, but I don't need to do that.
The main benefit is how little data I need for the dev db. It's about 12000 lines of xml, and handles populating maybe 30 different tables. Some small core tables persist as I don't write to them and many tables are empty because I do not use them.
The database is a representative sample, and is very small. Small enough to edit as a text file, and only a few seconds to populate each time I run tests.
Here's what it looks like at the top of each PHPUnit test. There's good documentation for PHPUnit and DbUnit
<?php
require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'top.php';
require_once "PHPUnit/Extensions/Database/TestCase.php";
class SomeTest extends PHPUnit_Extensions_Database_TestCase
{
/**
* #return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
public function getConnection() {
$database = MY_DB
$hostname = MY_HOST
$user = MY_USER
$password = MY_PASS
$pdo = new PDO("mysql:host=$hostname;dbname=$database", $user, $password);
return $this->createDefaultDBConnection($pdo, $database);
}
/**
* #return PHPUnit_Extensions_Database_DataSet_IDataSet
*/
public function getDataSet() {
return $this->createXMLDataSet(dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'Tests/_files/seed.xml');
}
}
So, now you just need a seed file that DbUnit reads from to repopulate your database each time Unit tests are invoked.
Start by copying your complete database twice. One will be your dev database and the second will be your "pristine" database, that you can use to dump xml data in case you start having key issues.
Then, use something like my xml dumper againt the "prisine" database to get your xml dumps and begin building your seed file.
generate_flat_xml.php -tcatalog_product_entity -centity_id,entity_type_id,attribute_set_id,type_id,sku,has_options,required_options -oentity_id >> my_seed_file.xml
Edit the seed file to use only what you need. The small size of the dev db means you can examine differences just by looking at your database versus what's in the text files. Not to mention it is much faster having less data.

Resources