<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cristian Llanos</title>
    <description>The latest articles on DEV Community by Cristian Llanos (@cristianllanos).</description>
    <link>https://dev.to/cristianllanos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F29360%2F25230132-fa3b-48d8-9fa1-8623c941efcf.jpeg</url>
      <title>DEV Community: Cristian Llanos</title>
      <link>https://dev.to/cristianllanos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cristianllanos"/>
    <language>en</language>
    <item>
      <title>How to migrate a MySQL Database from DigitalOcean to AWS RDS</title>
      <dc:creator>Cristian Llanos</dc:creator>
      <pubDate>Sun, 09 May 2021 15:58:39 +0000</pubDate>
      <link>https://dev.to/cristianllanos/how-to-migrate-a-mysql-database-from-digitalocean-to-aws-rds-3o82</link>
      <guid>https://dev.to/cristianllanos/how-to-migrate-a-mysql-database-from-digitalocean-to-aws-rds-3o82</guid>
      <description>&lt;h2&gt;
  
  
  Objective
&lt;/h2&gt;

&lt;p&gt;At the end of this process, we'll have successfully moved our selected MySQL schemas onto another MySQL Database (to AWS RDS for instance). We'll make use of some automated bash scripts to ease our way.&lt;/p&gt;

&lt;p&gt;Warning: the strategy shown in this guide will incur downtime for the clients of our databases while the migration process is running.  Use this guide as a learning resource at your own risk.&lt;/p&gt;

&lt;p&gt;If you are looking for the lowest migration downtime possible, I suggest having a look at &lt;a href="https://aws.amazon.com/es/dms/"&gt;AWS Database Migration Service&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have the following binaries on your server (versions used on this guide have been provided as a reference).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mysqldump (Ver 10.13 Distrib 5.7.33)&lt;/li&gt;
&lt;li&gt;mysql (client Ver 14.14 Distrib 5.7.33)&lt;/li&gt;
&lt;li&gt;bash (version 4.4.20(1)-release)&lt;/li&gt;
&lt;li&gt;date (GNU coreutils 8.28)&lt;/li&gt;
&lt;li&gt;Both Source and Destination Databases were previously created and are syntax compatible. Users and passwords have already been created for the migration, as well&lt;/li&gt;
&lt;li&gt;You already know how to log in to your DigitalOcean server and are comfortable using a command-line text editor such as Vim, Nano, Emacs (whichever works for you on your server)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Database Credentials
&lt;/h2&gt;

&lt;p&gt;Create a password file &lt;code&gt;~/.mysql_source_config&lt;/code&gt; and put the Source Database password using the following structure for &lt;code&gt;mysqldump&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;[&lt;span class="n"&gt;mysqldump&lt;/span&gt;]
&lt;span class="n"&gt;password&lt;/span&gt;=&lt;span class="n"&gt;the_password&lt;/span&gt;
&lt;span class="n"&gt;host&lt;/span&gt;=&lt;span class="n"&gt;localhost&lt;/span&gt;
&lt;span class="n"&gt;port&lt;/span&gt;=&lt;span class="m"&gt;3306&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set recommended permissions to protect the file from prying eyes. The command &lt;code&gt;chmod 600 &amp;lt;file&amp;gt;&lt;/code&gt; gives read and write permission only to the owner of the file (the system user who creates it in this case).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.mysql_source_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If the previous command did not work for you it may be due to a lack of permissions from your logged-in user.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's do the same process and store the destination MySQL database password by creating a &lt;code&gt;~/.mysql_destination_config&lt;/code&gt;. The config name will be targeting &lt;code&gt;mysql&lt;/code&gt; in this case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;[&lt;span class="n"&gt;mysql&lt;/span&gt;]
&lt;span class="n"&gt;password&lt;/span&gt;=&lt;span class="n"&gt;the_password&lt;/span&gt;
&lt;span class="n"&gt;host&lt;/span&gt;=&lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;aws&lt;/span&gt;-&lt;span class="n"&gt;rds&lt;/span&gt;-&lt;span class="n"&gt;host&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;span class="n"&gt;port&lt;/span&gt;=&lt;span class="m"&gt;3306&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And don't forget about its permissions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.mysql_destination_config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Backing up the database
&lt;/h2&gt;

&lt;p&gt;We can do it by exporting all schemas, but we'll do it this time by providing which schemas we want to migrate (&lt;code&gt;a_database_schema&lt;/code&gt; and &lt;code&gt;another_database_schema&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysqldump &lt;span class="nt"&gt;--defaults-extra-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/.mysql_source_config"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="nt"&gt;--databases&lt;/span&gt; a_database_schema another_database_schema &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; backup-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y_%m_%d_%H_%M_%S"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The previous command uses &lt;code&gt;root&lt;/code&gt; as the source database username and it's reading the password from &lt;code&gt;~/.mysql_source_config&lt;/code&gt;. The output of this command will be a file containing the DDL of our schemas, tables, and inserts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why have you separated the password from the command?
&lt;/h2&gt;

&lt;p&gt;Two reasons come to my mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; wise it's preferable to have them in different files to prevent us from running commands with the password in it. Remember that all commands we run on the terminal will end up in the history file. And we don't want to leak our password by accident&lt;/li&gt;
&lt;li&gt;It becomes easier to automate other commands/scripts that may need the same password by &lt;strong&gt;reusing the same file&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a script directory
&lt;/h2&gt;

&lt;p&gt;We need a place to put the scripts we are going to create&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Let's place ourselves in the user directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;

&lt;span class="c"&gt;# And create ~/bin directory if it does not exist&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;bin

&lt;span class="c"&gt;# We need to set appropriate permissions&lt;/span&gt;
&lt;span class="c"&gt;# Allowing read, write and execute access only to the owner of the file&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have to tell the system where to find our executable files. We need to add the following line to our shell configuration (in this case &lt;code&gt;~/.bashrc&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:&lt;span class="nv"&gt;$HOME&lt;/span&gt;/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a backup script
&lt;/h2&gt;

&lt;p&gt;Let's create a runnable script &lt;code&gt;~/bin/mysql-backup&lt;/code&gt; that will help us test our backup command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Let's navigate inside our scripts directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/bin

&lt;span class="c"&gt;# And create a new file&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;mysql-backup

&lt;span class="c"&gt;# Don't forget to protect the file&lt;/span&gt;
&lt;span class="c"&gt;# This time we'll make it executable since this file will become our backup script&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 mysql-backup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's put our backup command inside this new file &lt;code&gt;mysql-backup&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# This command will output a file with the DDL to recreate our schemas, tables, and values&lt;/span&gt;

&lt;span class="c"&gt;# If no parameter has been given, we'll use this name for the generated file&lt;/span&gt;
&lt;span class="nv"&gt;DEFAULT_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backup-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y_%m_%d_%H_%M_%S"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.sql

mysqldump &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;--defaults-extra-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/.mysql_source_config"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;--databases&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
            a_database_schema &lt;span class="se"&gt;\&lt;/span&gt;
            another_database_schema &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$DEFAULT_FILE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure &lt;code&gt;--user&lt;/code&gt; and &lt;code&gt;--databases&lt;/code&gt; schemas match yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a restore script
&lt;/h2&gt;

&lt;p&gt;Let's create another runnable script that uses the previous command's output to restore it on another database: &lt;code&gt;~/bin/mysql-restore&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Let's place ourselves in the previously created ~/bin directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/bin

&lt;span class="c"&gt;# And create a new file&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;mysql-restore

&lt;span class="c"&gt;# Don't forget to protect the file&lt;/span&gt;
&lt;span class="c"&gt;# We'll make it executable since this file will become our restauration script&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 mysql-restore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents of the file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# This command will take a SQL file and execute it on the Destination Database&lt;/span&gt;

mysql &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--defaults-extra-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/.mysql_destination_config"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;migration &lt;span class="se"&gt;\&lt;/span&gt;
        &amp;lt; &lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure &lt;code&gt;--user&lt;/code&gt; matches yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a migration script
&lt;/h2&gt;

&lt;p&gt;Let's create a runnable script that will integrate the previous commands to do a synchronous migration &lt;code&gt;~/bin/mysql-migrate&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Let's place ourselves in the previously created ~/bin directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/bin

&lt;span class="c"&gt;# And create a new file&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;mysql-migrate

&lt;span class="c"&gt;# Don't forget to protect the file&lt;/span&gt;
&lt;span class="c"&gt;# We'll make it executable since this file will become our restauration script&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 mysql-migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents of the file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# A backup file will be created with the SQL needed for the migration.&lt;/span&gt;
&lt;span class="c"&gt;# Feel free to delete it after the migration has run&lt;/span&gt;

&lt;span class="c"&gt;# Append the timestamp to the name of the generated file&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backup-&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +&lt;span class="s2"&gt;"%Y_%m_%d_%H_%M_%S"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;.sql

&lt;span class="nb"&gt;echo &lt;/span&gt;Making backup file from Source Database
mysql-backup &lt;span class="nv"&gt;$BACKUP_FILE&lt;/span&gt;

&lt;span class="nb"&gt;echo &lt;/span&gt;Restoring on Destination Database
mysql-restore &lt;span class="nv"&gt;$BACKUP_FILE&lt;/span&gt;

&lt;span class="nb"&gt;echo &lt;/span&gt;Done!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Migration Strategy
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add password configurations for source and destination databases on the source server. Make sure all credentials are working properly&lt;/li&gt;
&lt;li&gt;Place migration commands on a PATH directory (we created one ~/bin). Make sure you have already tested the commands are working as expected and there are no permission errors when running them.&lt;/li&gt;
&lt;li&gt;Prepare a list of environment variables to update on Database client servers if applicable&lt;/li&gt;
&lt;li&gt;Turn off Source Database writes on all clients. Run &lt;code&gt;php artisan down&lt;/code&gt; on Laravel projects&lt;/li&gt;
&lt;li&gt;Place your terminal in an empty directory (preferably), run &lt;code&gt;mysql-migrate&lt;/code&gt; and wait until it finishes&lt;/li&gt;
&lt;li&gt;Point all clients to the Destination Database host using their new credentials. Change environment variables on Database clients if needed. If applicable, update &lt;code&gt;.env&lt;/code&gt; file on Laravel projects&lt;/li&gt;
&lt;li&gt;Turn back on Database writes. This time pointing to the destination database. Run &lt;code&gt;php artisan up&lt;/code&gt; on Laravel projects&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>digitalocean</category>
      <category>database</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
