Skip to content

Commit

Permalink
lint and license
Browse files Browse the repository at this point in the history
  • Loading branch information
paulczar committed Sep 20, 2014
1 parent 19658c4 commit 891d4a8
Show file tree
Hide file tree
Showing 14 changed files with 95 additions and 95 deletions.
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2014 Paul Czarkowski

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
129 changes: 58 additions & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ This docker image contains Percona with the galera extentions and XtraBackup ins

If etcd is available it will automatically cluster itself with Galera and the XtraBackup SST.

Fetching
========

$ git clone https://github.com/paulczar/docker-percona_galera.git
cd docker-percona_galera

Building
========

```console
$ docker build -t paulczar/percona-galera .
```
$ docker build -t paulczar/percona-galera .

Running
=======
Expand All @@ -20,77 +24,68 @@ Just a database

MySQL root user is available from localhost without a password. a default user/pass pair of admin/admin is pulled in from environment variables which has root like perms. set it to something sensible.

```console
$ docker run -d -e MYSQL_USER=admin -e MYSQL_PASS=lolznopass paulczar/percona-galera
==> $HOST not set. booting mysql without clustering.
==> An empty or uninitialized database is detected in /var/lib/mysql
==> Creating database...
==> Done!
==> starting mysql in order to set up passwords
==> sleeping for 20 seconds, then testing if DB is up
140920 16:22:26 mysqld_safe Logging to '/var/log/mysql/error.log'.
140920 16:22:26 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
140920 16:22:26 mysqld_safe Skipping wsrep-recover for empty datadir: /var/lib/mysql
140920 16:22:26 mysqld_safe Assigning 00000000-0000-0000-0000-000000000000:-1 to wsrep_start_position
==> stopping mysql after setting up passwords
140920 16:22:47 mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
140920 16:22:48 mysqld_safe Logging to '/var/log/mysql/error.log'.
140920 16:22:48 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
140920 16:22:48 mysqld_safe Skipping wsrep-recover for empty datadir: /var/lib/mysql
140920 16:22:48 mysqld_safe Assigning 00000000-0000-0000-0000-000000000000:-1 to wsrep_start_position
```
$ docker run -d -e MYSQL_USER=admin -e MYSQL_PASS=lolznopass paulczar/percona-galera
==> $HOST not set. booting mysql without clustering.
==> An empty or uninitialized database is detected in /var/lib/mysql
==> Creating database...
==> Done!
==> starting mysql in order to set up passwords
==> sleeping for 20 seconds, then testing if DB is up
140920 16:22:26 mysqld_safe Logging to '/var/log/mysql/error.log'.
140920 16:22:26 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
140920 16:22:26 mysqld_safe Skipping wsrep-recover for empty datadir: /var/lib/mysql
140920 16:22:26 mysqld_safe Assigning 00000000-0000-0000-0000-000000000000:-1 to wsrep_start_position
==> stopping mysql after setting up passwords
140920 16:22:47 mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
140920 16:22:48 mysqld_safe Logging to '/var/log/mysql/error.log'.
140920 16:22:48 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
140920 16:22:48 mysqld_safe Skipping wsrep-recover for empty datadir: /var/lib/mysql
140920 16:22:48 mysqld_safe Assigning 00000000-0000-0000-0000-000000000000:-1 to wsrep_start_position

Galera Cluster
--------------

When etcd is available the container will check to see if there's an existing cluster, if so it will join it. If not it will perform an election that will last for 5 minutes. During that time the first server that can grab a lock becomes the leader and any other nodes will wait until that server is ready before starting. If the leader fails to start the election is busted and all nodes will need to be destroyed until the 5 minutes passes.

An example Vagrantfile is provided which will start a 3 node `CoreOS` cluster each node running a
database with replication automatically set up.
database with replication automatically set up.

```console
$ vagrant up
$ ssh coreos-01
$ watch docker ps
```
$ vagrant up
$ ssh coreos-01
$ watch docker ps

At this point the coreos user-data is starting the database. It has to be downloaded from the docker hub first, and this can take some time. Eventually the container will start and you'll see this in the console:

```console
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
912ad42a4d1a paulczar/percona-galera:latest "/app/bin/boot" About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, 0.0.0.0:4444->4444/tcp, 0.0.0.0:4567->4567/tcp, 0.0.0.0:4568->4568/tcp database
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
912ad42a4d1a paulczar/percona-galera:latest "/app/bin/boot" About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, 0.0.0.0:4444->4444/tcp, 0.0.0.0:4567->4567/tcp, 0.0.0.0:4568->4568/tcp database

Next we can watch mysql starting by utilizing `journalctl`

```console
$ journalctl -f -u database
Sep 20 18:54:36 core-01 sh[1489]: Starting MySQL for reals
Sep 20 18:54:36 core-01 sh[1489]: ==> Performing Election...
Sep 20 18:54:36 core-01 sh[1489]: -----> Hurruh I win!
Sep 20 18:54:36 core-01 sh[1489]: ==> sleeping for 20 seconds, then testing if DB is up.
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Logging to '/var/lib/mysql/912ad42a4d1a.err'.
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Skipping wsrep-recover for 82f9ad85-40f7-11e4-9f0d-1eed76224be8:0 pair
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Assigning 82f9ad85-40f7-11e4-9f0d-1eed76224be8:0 to wsrep_start_position
Sep 20 18:54:56 core-01 sh[1489]: ==> database running...
```
$ journalctl -f -u database
Sep 20 18:54:36 core-01 sh[1489]: Starting MySQL for reals
Sep 20 18:54:36 core-01 sh[1489]: ==> Performing Election...
Sep 20 18:54:36 core-01 sh[1489]: -----> Hurruh I win!
Sep 20 18:54:36 core-01 sh[1489]: ==> sleeping for 20 seconds, then testing if DB is up.
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Logging to '/var/lib/mysql/912ad42a4d1a.err'.
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Skipping wsrep-recover for 82f9ad85-40f7-11e4-9f0d-1eed76224be8:0 pair
Sep 20 18:54:36 core-01 sh[1489]: 140920 18:54:36 mysqld_safe Assigning 82f9ad85-40f7-11e4-9f0d-1eed76224be8:0 to wsrep_start_position
Sep 20 18:54:56 core-01 sh[1489]: ==> database running...

At this point we can actually console into the container by running `database` which is a function we inject in the user-data to use `nsenter` to get a shell inside the database container...


```console
$ database
root@e9682b05cf5e:/# mysql -e "show status like 'wsrep_cluster%'"
+--------------------------+--------------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------------+
| wsrep_cluster_conf_id | 3 |
| wsrep_cluster_size | 3 |
| wsrep_cluster_state_uuid | 1b92a583-40f6-11e4-ad62-46aacd6cd67e |
| wsrep_cluster_status | Primary |
+--------------------------+--------------------------------------+
```
$ database
root@e9682b05cf5e:/# mysql -e "show status like 'wsrep_cluster%'"
+--------------------------+--------------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------------+
| wsrep_cluster_conf_id | 3 |
| wsrep_cluster_size | 3 |
| wsrep_cluster_state_uuid | 1b92a583-40f6-11e4-ad62-46aacd6cd67e |
| wsrep_cluster_status | Primary |
+--------------------------+--------------------------------------+

There are some hints that you need to pass via environment variables to make this magic happen.
These are provided in the `database` unit in `user-data.erb`. Explore `user-data.erb`, `bin/boot`, and `bin/functions` to see how the sausage is made.

Expand All @@ -107,32 +102,24 @@ GarbD

If you want to stick to a two node cluster you can start garbd to act as the arbiter.

```console
$ eval `cat /etc/environment`
$ /usr/bin/docker run --name database-garbd --rm -p 3306:3306 -p 4444:4444 -p 4567:4567 -p 4568:4568 -e PUBLISH=4567 -e HOST=$COREOS_PRIVATE_IPV4 -e CLUSTER=openstack paulczar/percona-galera:latest /app/bin/garbd
```
$ eval `cat /etc/environment`
$ /usr/bin/docker run --name database-garbd --rm -p 3306:3306 -p 4444:4444 -p 4567:4567 -p 4568:4568 -e PUBLISH=4567 -e HOST=$COREOS_PRIVATE_IPV4 -e CLUSTER=openstack paulczar/percona-galera:latest /app/bin/garbd

Load Balancer
-------------

You can use an external load balancer if you have one DB per host. If you're getting fancy you can also run a local haproxy load balancer ( or multiples ) which will load balance ( round robin, nothing fancy ) database connections between your nodes

```console
$ eval `cat /etc/environment`
$ /usr/bin/docker run --name database-loadbalancer --rm -p 3307:3307 -p 8888:8080 -e PUBLISH=3307 -e HOST=$COREOS_PRIVATE_IPV4 paulczar/percona-galera:latest /app/bin/loadbalancer
```

$ eval `cat /etc/environment`
$ /usr/bin/docker run --name database-loadbalancer --rm -p 3307:3307 -p 8888:8080 -e PUBLISH=3307 -e HOST=$COREOS_PRIVATE_IPV4 paulczar/percona-galera:latest /app/bin/loadbalancer

Development
-----------

You can use vagrant in developer mode which will install the service but not run it. it will also enable debug mode on the start script, share the local path into `/home/coreos/share` via `nfs` and build the image locally. This takes quite a while as it builds the image on each VM, but once its up further rebuilds should be quick thanks to the caches.

```console
$ dev=1 vagrant up
$ vagrant ssh core-01

```
$ dev=1 vagrant up
$ vagrant ssh core-01


Author(s)
Expand All @@ -155,4 +142,4 @@ Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
4 changes: 2 additions & 2 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require_relative CONFIG if File.exist?(CONFIG)

if ARGV.include? 'up'
puts 'rewriting userdata'
write_user_data($num_instances)
write_user_data($num_instances)
end

Vagrant.configure('2') do |config|
Expand Down Expand Up @@ -80,7 +80,7 @@ Vagrant.configure('2') do |config|
if ENV['dev']
c.vm.synced_folder '.', '/home/core/share', id: 'core', nfs: true, mount_options: ['nolock,vers=3,udp']
end

if File.exist?(CLOUD_CONFIG_PATH)
c.vm.provision :file, source: "#{CLOUD_CONFIG_PATH}", destination: '/tmp/vagrantfile-user-data'
c.vm.provision :shell, inline: 'mv /tmp/vagrantfile-user-data /var/lib/coreos-vagrant/', privileged: true
Expand Down
2 changes: 1 addition & 1 deletion bin/boot
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cluster_members

echo Starting MySQL for reals

if [[ -z $CLUSTER_MEMBERS ]]; then
if [[ -z $CLUSTER_MEMBERS ]]; then
# Perform Election
echo "==> Performing Election..."
etcdctl $ETCD_OPTIONS ls $ETCD_PATH/election >/dev/null 2>&1 || etcdctl $ETCD_OPTIONS mkdir $ETCD_PATH/election >/dev/null 2>&1
Expand Down
4 changes: 2 additions & 2 deletions bin/functions
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ function configure_etcd() {
export ETCD="$ETCD_HOST:$ETCD_PORT"
export ETCD_PATH=${ETCD_PATH:-/database}
export ETCD_TTL=${ETCD_TTL:-10}
export ETCD_OPTIONS="--no-sync -C $ETCD"
export ETCD_OPTIONS="--no-sync -C $ETCD"
# wait for etcd to be available
until etcdctl --no-sync -C $ETCD ls >/dev/null 2>&1; do
echo "echo ==> waiting for etcd at $ETCD..."
sleep $(($ETCD_TTL/2)) # sleep for half the TTL
done
# wait until etcd has discarded potentially stale values
sleep $(($ETCD_TTL+1))
}
}
2 changes: 1 addition & 1 deletion bin/garbd
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ etcd_make_directory cluster/galeraEndpoints

# I don't want to be the first guy in the cluster.
while [[ -z $(etcdctl --no-sync -C $ETCD ls $ETCD_PATH/cluster/galeraEndpoints | awk -F/ '{print $6}' | xargs | sed 's/ /,/') ]]
do
do
echo "waiting for other nodes"
sleep 10
done
Expand Down
2 changes: 1 addition & 1 deletion bin/loadbalancer
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function etcd_set {
PORT=${PUBLISH:-3307}
PROTO=${PROTO:-tcp}

etcd_set port $PORT
etcd_set port $PORT
etcd_set host $HOST

# wait for confd to run once and install initial templates
Expand Down
2 changes: 1 addition & 1 deletion config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def write_user_data(num_instances)
else
@etcd_discovery = "discovery: #{Net::HTTP.get(URI.parse('http://discovery.etcd.io/new'))}"
end
if ENV['dev']
if ENV['dev']
@command = 'stop'
@debug = 1
else
Expand Down
2 changes: 1 addition & 1 deletion templates/cluster.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ wsrep_certify_nonPK=1
wsrep_convert_LOCK_to_trx=0
wsrep_auto_increment_control=1
wsrep_causal_reads=0
wsrep_sst_method=xtrabackup
wsrep_sst_method=xtrabackup
2 changes: 1 addition & 1 deletion templates/database_creds
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ mysql -e 'SET wsrep_on=OFF; GRANT ALL PRIVILEGES ON *.* TO "{{ .database_credent
mysql -e 'SET wsrep_on=OFF; GRANT SUPER ON *.* TO "{{ .database_credentials_adminUser }}"@"%" WITH GRANT OPTION;'
mysql -e 'FLUSH PRIVILEGES;'

exit 0
exit 0
4 changes: 2 additions & 2 deletions templates/haproxy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ listen database_LB
option tcpka
option mysql-check user haproxy_check
{{range $server := .database_cluster_mysqlNodes}}
server {{Base $server.Key}} {{$server.Value}} check
server {{Base $server.Key}} {{$server.Value}} check
{{end}}

listen stats *:8080
Expand All @@ -24,4 +24,4 @@ listen stats *:8080
balance roundrobin
stats uri /
stats realm Haproxy\ Statistics
stats auth admin:admin
stats auth admin:admin
4 changes: 2 additions & 2 deletions templates/my.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# You can copy this file to one of:
# - "/etc/mysql/my.cnf" to set global options,
# - "~/.my.cnf" to set user-specific options.
#
#
# One can use all long options that the program supports.
# Run program with --help to get a list of available options and with
# --print-defaults to see which it would actually understand and use.
Expand Down Expand Up @@ -169,4 +169,4 @@ key_buffer = 16M
# * IMPORTANT: Additional settings that can override those from this file!
# The files must end with '.cnf', otherwise they'll be ignored.
#
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/conf.d/
12 changes: 6 additions & 6 deletions templates/utf8.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

[client]
# Default is Latin1, if you need UTF-8 set this (also in server section)
default-character-set = utf8
default-character-set = utf8

[mysqld]
#
# * Character sets
#
#
# Default is Latin1, if you need UTF-8 set all this (also in client section)
#
character-set-server = utf8
collation-server = utf8_general_ci
character_set_server = utf8
collation_server = utf8_general_ci
character-set-server = utf8
collation-server = utf8_general_ci
character_set_server = utf8
collation_server = utf8_general_ci
8 changes: 4 additions & 4 deletions user-data.erb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ coreos:
TimeoutStartSec=20m
ExecStartPre=/usr/bin/docker pull paulczar/percona-galera:latest
ExecStart=/bin/sh -c "/usr/bin/docker run --name database --rm -p 3306:3306 -p 4444:4444 -p 4567:4567 -p 4568:4568 -e PUBLISH=3306 -e HOST=$COREOS_PRIVATE_IPV4 -e CLUSTER=galera paulczar/percona-galera:latest"
ExecStop=/usr/bin/docker stop database
ExecStop=/usr/bin/docker stop database

write_files:
- path: /etc/motd
Expand All @@ -47,16 +47,16 @@ write_files:
content: |
function nse() {
sudo nsenter --pid --uts --mount --ipc --net --target $(docker inspect --format="{{ .State.Pid }}" $1)
}
}
- path: /etc/profile.d/database_shell.sh
permissions: '0755'
content: |
function database() {
sudo nsenter --pid --uts --mount --ipc --net --target $(docker inspect --format="{{ .State.Pid }}" database)
}
}
- path: /etc/profile.d/rebuild.sh
permissions: '0755'
content: |
function rebuild() {
docker build -t paulczar/percona-galera /home/core/share
}
}

0 comments on commit 891d4a8

Please sign in to comment.