Initial Commit
This commit is contained in:
parent
baa561c56e
commit
8430ff9304
19 changed files with 562 additions and 1 deletions
5
.dockerignore
Normal file
5
.dockerignore
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
docker-compose.yml
|
||||||
|
./examples/*
|
||||||
|
.tool-versions
|
1
.tool-versions
Normal file
1
.tool-versions
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ruby 3.3.5
|
35
Dockerfile
Normal file
35
Dockerfile
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
FROM ruby:3.3-alpine
|
||||||
|
|
||||||
|
RUN mkdir /backups
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
build-base \
|
||||||
|
libffi-dev \
|
||||||
|
linux-headers \
|
||||||
|
postgresql-dev \
|
||||||
|
tzdata \
|
||||||
|
git \
|
||||||
|
curl
|
||||||
|
|
||||||
|
RUN gem install bundler -v 2.6.7
|
||||||
|
|
||||||
|
COPY entrypoint.sh /
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /app
|
||||||
|
# Copy the Gemfile and Gemfile.lock
|
||||||
|
COPY ./app/Gemfile ./app/Gemfile.lock /app/
|
||||||
|
# Install the gems
|
||||||
|
RUN bundle config set --local deployment 'true' && \
|
||||||
|
bundle config set --local path 'vendor/bundle' && \
|
||||||
|
bundle config set --local without 'development test' && \
|
||||||
|
bundle install
|
||||||
|
|
||||||
|
|
||||||
|
COPY ./app/ /app/
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
CMD ["bundle", "exec", "ruby", "./app.rb"]
|
63
README.md
63
README.md
|
@ -1,3 +1,64 @@
|
||||||
# baktainer
|
# baktainer
|
||||||
|
Easily backup databases running in docker containers.
|
||||||
|
## Features
|
||||||
|
- Backup MySQL, PostgreSQL, MongoDB, and SQLite databases
|
||||||
|
- Run on a schedule using cron expressions
|
||||||
|
- Backup databases running in docker containers
|
||||||
|
- Define which databases to backup using docker labels
|
||||||
|
## Installation
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
baktainer:
|
||||||
|
image: jamez01/baktainer:latest
|
||||||
|
container_name: baktainer
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./backups:/backups
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- BT_CRON="0 0 * * *" # Backup every day at midnight
|
||||||
|
- "BT_DOCKER_URL=unix:///var/run/docker.sock"
|
||||||
|
- BT_THREADS=4
|
||||||
|
- BT_BACKUP_DIR=/backups
|
||||||
|
- BT_LOG_LEVEL=info
|
||||||
|
# Enable if using SSL over tcp
|
||||||
|
#- BT_SSL = true
|
||||||
|
#- BT_CA
|
||||||
|
#- BT_CERT
|
||||||
|
#- BT_KEY
|
||||||
|
```
|
||||||
|
|
||||||
Easily backup your docker databases
|
## Environment Variables
|
||||||
|
| Variable | Description | Default |
|
||||||
|
| -------- | ----------- | ------- |
|
||||||
|
| BT_CRON | Cron expression for scheduling backups | 0 0 * * * |
|
||||||
|
| BT_THREADS | Number of threads to use for backups | 4 |
|
||||||
|
| BT_BACKUP_DIR | Directory to store backups | /backups |
|
||||||
|
| BT_LOG_LEVEL | Log level (debug, info, warn, error) | info |
|
||||||
|
| BT_SSL | Enable SSL for docker connection | false |
|
||||||
|
| BT_CA | Path to CA certificate | none |
|
||||||
|
| BT_CERT | Path to client certificate | none |
|
||||||
|
| BT_KEY | Path to client key | none |
|
||||||
|
| BT_DOCKER_URL | Docker URL | unix:///var/run/docker.sock |
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Add labels to your docker containers to specify which databases to backup.
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:17
|
||||||
|
container_name: my-db
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- db:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: "${DB_BASE:-database}"
|
||||||
|
POSTGRES_USER: "${DB_USER:-user}"
|
||||||
|
POSTGRES_PASSWORD: "${DB_PASSWORD:-StrongPassword}"
|
||||||
|
labels:
|
||||||
|
- baktainer.backup: "true"
|
||||||
|
- baktainer.db.name: "my-db"
|
||||||
|
- baktainer.db.password: "StrongPassword"
|
||||||
|
- baktainer.db.engine: "postgres"
|
||||||
|
- baktainer.name: "MyApp"
|
||||||
|
```
|
||||||
|
|
7
app/Gemfile
Normal file
7
app/Gemfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
source 'https://rubygems.org'
|
||||||
|
gem 'base64', '~> 0.2.0'
|
||||||
|
gem 'concurrent-ruby', '~> 1.3.5'
|
||||||
|
gem 'docker-api', '~> 2.4.0'
|
||||||
|
gem 'cron_calc', '~> 1.0.0'
|
26
app/Gemfile.lock
Normal file
26
app/Gemfile.lock
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
base64 (0.2.0)
|
||||||
|
concurrent-ruby (1.3.5)
|
||||||
|
cron_calc (1.0.0)
|
||||||
|
docker-api (2.4.0)
|
||||||
|
excon (>= 0.64.0)
|
||||||
|
multi_json
|
||||||
|
excon (1.2.5)
|
||||||
|
logger
|
||||||
|
logger (1.7.0)
|
||||||
|
multi_json (1.15.0)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
x86_64-linux
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
base64 (~> 0.2.0)
|
||||||
|
concurrent-ruby (~> 1.3.5)
|
||||||
|
cron_calc (~> 1.0.0)
|
||||||
|
docker-api (~> 2.4.0)
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
2.6.2
|
33
app/app.rb
Normal file
33
app/app.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rubygems'
|
||||||
|
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib"
|
||||||
|
require 'bundler/setup'
|
||||||
|
require 'baktainer'
|
||||||
|
require 'baktainer/logger'
|
||||||
|
require 'baktainer/container'
|
||||||
|
require 'baktainer/backup_command'
|
||||||
|
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
options = {}
|
||||||
|
OptionParser.new do |opts|
|
||||||
|
opts.banner = 'Usage: baktainer.rb [options]'
|
||||||
|
|
||||||
|
opts.on('-N', '--now', 'Run immediately and exit.') do
|
||||||
|
options[:now] = true
|
||||||
|
end
|
||||||
|
end.parse!
|
||||||
|
|
||||||
|
LOGGER.info('Starting')
|
||||||
|
baktainer = Baktainer::Runner.new(
|
||||||
|
url: ENV['BT_DOCKER_URL'] || 'unix:///var/run/docker.sock',
|
||||||
|
ssl: ENV['BT_SSL'] || false,
|
||||||
|
ssl_options: {
|
||||||
|
ca_file: ENV['BT_CA'],
|
||||||
|
client_cert: ENV['BT_CERT'],
|
||||||
|
client_key: ENV['BT_KEY']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
baktainer.run
|
107
app/lib/baktainer.rb
Normal file
107
app/lib/baktainer.rb
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Baktainer is a class responsible for managing database backups using Docker containers.
|
||||||
|
#
|
||||||
|
# It supports the following database engines: PostgreSQL, MySQL, MariaDB, and Sqlite3.
|
||||||
|
#
|
||||||
|
# @example Initialize a Baktainer instance
|
||||||
|
# baktainer = Baktainer.new(url: 'unix:///var/run/docker.sock', ssl: true, ssl_options: {})
|
||||||
|
#
|
||||||
|
# @example Run the backup process
|
||||||
|
# baktainer.run
|
||||||
|
#
|
||||||
|
# @!attribute [r] SUPPORTED_ENGINES
|
||||||
|
# @return [Array<String>] The list of supported database engines.
|
||||||
|
#
|
||||||
|
# @param url [String] The Docker API URL. Defaults to 'unix:///var/run/docker.sock'.
|
||||||
|
# @param ssl [Boolean] Whether to use SSL for Docker API communication. Defaults to false.
|
||||||
|
#
|
||||||
|
# @method perform_backup
|
||||||
|
# Starts the backup process by searching for Docker containers and performing backups.
|
||||||
|
# Logs the process at various stages.
|
||||||
|
#
|
||||||
|
# @method run
|
||||||
|
# Schedules and runs the backup process at a specified time.
|
||||||
|
# If the time is invalid or not provided, defaults to 05:00.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @method setup_ssl
|
||||||
|
# Configures SSL settings for Docker API communication if SSL is enabled.
|
||||||
|
# Uses environment variables `BT_CA`, `BT_CERT`, and `BT_KEY` for SSL certificates and keys.
|
||||||
|
module Baktainer
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'docker-api'
|
||||||
|
require 'cron_calc'
|
||||||
|
require 'concurrent/executor/fixed_thread_pool'
|
||||||
|
require 'baktainer/logger'
|
||||||
|
require 'baktainer/container'
|
||||||
|
require 'baktainer/backup_command'
|
||||||
|
|
||||||
|
STDOUT.sync = true
|
||||||
|
|
||||||
|
|
||||||
|
class Baktainer::Runner
|
||||||
|
SUPPORTED_ENGINES = %w[postgres postgres-all sqlite mongodb mysql mariadb].freeze
|
||||||
|
def initialize(url: 'unix:///var/run/docker.sock', ssl: false, ssl_options: {}, threads: 5)
|
||||||
|
@pool = Concurrent::FixedThreadPool.new(threads)
|
||||||
|
@url = url
|
||||||
|
@ssl = ssl
|
||||||
|
@ssl_options = ssl_options
|
||||||
|
Docker.url = @url
|
||||||
|
setup_ssl
|
||||||
|
LOGGER.level = ENV['LOG_LEVEL'] || :debug
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform_backup
|
||||||
|
LOGGER.info('Starting backup process.')
|
||||||
|
LOGGER.debug('Docker Searching for containers.')
|
||||||
|
Containers.find_all.each do |container|
|
||||||
|
# @pool.post do
|
||||||
|
begin
|
||||||
|
LOGGER.info("Backing up container #{container.name} with engine #{container.engine}.")
|
||||||
|
container.backup
|
||||||
|
LOGGER.info("Backup completed for container #{container.name}.")
|
||||||
|
rescue StandardError => e
|
||||||
|
LOGGER.error("Error backing up container #{container.name}: #{e.message}")
|
||||||
|
LOGGER.debug(e.backtrace.join("\n"))
|
||||||
|
end
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
run_at = ENV['BT_CRON'] || '0 0 * * *'
|
||||||
|
begin
|
||||||
|
@cron = CronCalc.new(run_at)
|
||||||
|
rescue
|
||||||
|
LOGGER.error("Invalid cron format for BT_CRON: #{run_at}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
loop do
|
||||||
|
now = Time.now
|
||||||
|
next_run = @cron.next.first
|
||||||
|
# sleep_duration = next_run - now
|
||||||
|
sleep_duration = 5
|
||||||
|
LOGGER.info("Sleeping for #{sleep_duration} seconds until #{next_run}.")
|
||||||
|
sleep(sleep_duration)
|
||||||
|
perform_backup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def setup_ssl
|
||||||
|
return unless @ssl
|
||||||
|
|
||||||
|
@cert_store = OpenSSL::X509::Store.new
|
||||||
|
@cerificate = OpenSSL::X509::Certificate.new(ENV['BT_CA'])
|
||||||
|
@cert_store.add_cert(@cerificate)
|
||||||
|
Docker.options = {
|
||||||
|
client_cert_data: ENV['BT_CERT'],
|
||||||
|
client_key_data: ENV['BT_KEY'],
|
||||||
|
ssl_cert_store: @cert_store,
|
||||||
|
scheme: 'https'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
19
app/lib/baktainer/backup_command.rb
Normal file
19
app/lib/baktainer/backup_command.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'baktainer/mysql'
|
||||||
|
require 'baktainer/postgres'
|
||||||
|
require 'baktainer/mariadb'
|
||||||
|
require 'baktainer/sqlite'
|
||||||
|
|
||||||
|
# This class is responsible for generating the backup command for the database engine
|
||||||
|
# It uses the environment variables to set the necessary parameters for the backup command
|
||||||
|
# The class methods return a hash with the environment variables and the command to run
|
||||||
|
# The class methods are used in the Baktainer::Container class to generate the backup command
|
||||||
|
class Baktainer::BackupCommand
|
||||||
|
def custom(command: nil)
|
||||||
|
{
|
||||||
|
env: [],
|
||||||
|
cmd: command.split(/\s+/)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
111
app/lib/baktainer/container.rb
Normal file
111
app/lib/baktainer/container.rb
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# The `Container` class represents a container abstraction within the Baktainer application.
|
||||||
|
# It is responsible for encapsulating the logic and behavior related to managing containers.
|
||||||
|
# This class serves as a core component of the application, providing methods and attributes
|
||||||
|
# to interact with and manipulate container instances.
|
||||||
|
|
||||||
|
require 'fileutils'
|
||||||
|
require 'date'
|
||||||
|
|
||||||
|
class Baktainer::Container
|
||||||
|
def initialize(container)
|
||||||
|
@container = container
|
||||||
|
@backup_command = Baktainer::BackupCommand.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
@container.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def labels
|
||||||
|
@container.info['Labels']
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
labels["baktainer.name"] || @container.info['Names'].first
|
||||||
|
end
|
||||||
|
|
||||||
|
def state
|
||||||
|
@container.info['State']
|
||||||
|
end
|
||||||
|
|
||||||
|
def running?
|
||||||
|
state == 'running'
|
||||||
|
end
|
||||||
|
|
||||||
|
def engine
|
||||||
|
labels['baktainer.db.engine']&.downcase
|
||||||
|
end
|
||||||
|
|
||||||
|
def login
|
||||||
|
labels['baktainer.db.user'] || nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def password
|
||||||
|
labels['baktainer.db.password'] || nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def database
|
||||||
|
labels['baktainer.db.name'] || nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def validdate
|
||||||
|
return raise 'Unable to parse container' if @container.nil?
|
||||||
|
return raise 'Container not running' if state.nil? || state != 'running'
|
||||||
|
return raise 'Use docker labels to define db settings' if labels.nil? || labels.empty?
|
||||||
|
if labels['baktainer.backup']&.downcase != 'true'
|
||||||
|
return raise 'Backup not enabled for this container. Set docker label baktainer.backup=true'
|
||||||
|
end
|
||||||
|
LOGGER.debug("Container labels['baktainer.db.engine']: #{labels['baktainer.db.engine']}")
|
||||||
|
if engine.nil? || !@backup_command.respond_to?(engine.to_sym)
|
||||||
|
return raise 'DB Engine not defined. Set docker label baktainer.engine.'
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def backup
|
||||||
|
LOGGER.debug("Starting backup for container #{name} with engine #{engine}.")
|
||||||
|
return unless validdate
|
||||||
|
LOGGER.debug("Container #{name} is valid for backup.")
|
||||||
|
backup_dir = "/backups/#{Date.today}"
|
||||||
|
FileUtils.mkdir_p("/backups/#{Date.today}") unless Dir.exist?(backup_dir)
|
||||||
|
sql_dump = File.open("/backups/#{Date.today}/#{name}-#{Time.now.to_i}.sql", 'w')
|
||||||
|
command = backup_command
|
||||||
|
LOGGER.debug("Backup command environment variables: #{command[:env].inspect}")
|
||||||
|
@container.exec(command[:cmd], env: command[:env]) do |stream, chunk|
|
||||||
|
sql_dump.write(chunk) if stream == :stdout
|
||||||
|
LOGGER.warn("#{name} stderr: #{chunk}") if stream == :stderr
|
||||||
|
end
|
||||||
|
sql_dump.close
|
||||||
|
LOGGER.debug("Backup completed for container #{name}.")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def backup_command
|
||||||
|
if @backup_command.respond_to?(engine.to_sym)
|
||||||
|
return @backup_command.send(engine.to_sym, login: login, password: password, database: database)
|
||||||
|
elsif engine == 'custom'
|
||||||
|
return @backup_command.custom(command: labels['baktainer.command']) || raise('Custom command not defined. Set docker label bt_command.')
|
||||||
|
else
|
||||||
|
raise "Unsupported engine: #{engine}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# :NODOC:
|
||||||
|
class Containers
|
||||||
|
def self.find_all
|
||||||
|
LOGGER.debug('Searching for containers with backup labels.')
|
||||||
|
containers = Docker::Container.all.select do |container|
|
||||||
|
container.info['Labels']['baktainer.backup'] == 'true'
|
||||||
|
end
|
||||||
|
LOGGER.debug("Found #{containers.size} containers with backup labels.")
|
||||||
|
LOGGER.debug(containers.first.class)
|
||||||
|
containers.map do |container|
|
||||||
|
Baktainer::Container.new(container)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
22
app/lib/baktainer/logger.rb
Normal file
22
app/lib/baktainer/logger.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'logger'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
# Log messages in JSON format
|
||||||
|
class JsonLogger < Logger
|
||||||
|
def format_message(severity, timestamp, progname, msg)
|
||||||
|
{
|
||||||
|
severity: severity,
|
||||||
|
timestamp: timestamp,
|
||||||
|
progname: progname || 'backtainer',
|
||||||
|
message: msg
|
||||||
|
}.to_json + "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(STDOUT)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
LOGGER = JsonLogger.new
|
11
app/lib/baktainer/mariadb.rb
Normal file
11
app/lib/baktainer/mariadb.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# mariadb backup command generator
|
||||||
|
class Baktainer::BackupCommand
|
||||||
|
def mariadb(login:, password:, database:)
|
||||||
|
{
|
||||||
|
env: [],
|
||||||
|
cmd: ['mariadb-dump', "-u#{login}", "-p#{password}", '--databases', database]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
11
app/lib/baktainer/mysql.rb
Normal file
11
app/lib/baktainer/mysql.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# MySQL backup command generator
|
||||||
|
class Baktainer::BackupCommand
|
||||||
|
def mysql(login:, password:, database:)
|
||||||
|
{
|
||||||
|
env: [],
|
||||||
|
cmd: ['mysqldump', '-u', login, "-p#{password}", database]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
28
app/lib/baktainer/postgres.rb
Normal file
28
app/lib/baktainer/postgres.rb
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Postgres backup command generator
|
||||||
|
class Baktainer::BackupCommand
|
||||||
|
def postgres(login: 'postgres', password: nil, database: nil, all: false)
|
||||||
|
{
|
||||||
|
env: [
|
||||||
|
"PGPASSWORD=#{password}",
|
||||||
|
"PGUSER=#{login}",
|
||||||
|
"PGDATABASE=#{database}",
|
||||||
|
'PGAPPNAME=Baktainer'
|
||||||
|
],
|
||||||
|
cmd: [all ? 'pg_dumpall' : 'pg_dump']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def postgres_all(login: 'postgres', password: nil, database: nil)
|
||||||
|
posgres(login: login, password: password, database: database, all: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def postgresql(*args)
|
||||||
|
postgres(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def postgresql_all(*args)
|
||||||
|
postgres_all(*args)
|
||||||
|
end
|
||||||
|
end
|
13
app/lib/baktainer/sqlite.rb
Normal file
13
app/lib/baktainer/sqlite.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# sqlite backup command generator
|
||||||
|
class Baktainer::BackupCommand
|
||||||
|
class << self
|
||||||
|
def sqlite(database:, _login: nil, _password: nil)
|
||||||
|
{
|
||||||
|
env: [],
|
||||||
|
cmd: ['sqlite3', database, '.dump']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
backups/2025-04-14/MyApp-1744637779.sql
Normal file
23
backups/2025-04-14/MyApp-1744637779.sql
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Dumped from database version 17.4
|
||||||
|
-- Dumped by pg_dump version 17.4
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET lock_timeout = 0;
|
||||||
|
SET idle_in_transaction_session_timeout = 0;
|
||||||
|
SET transaction_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = on;
|
||||||
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET xmloption = content;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET row_security = off;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump complete
|
||||||
|
--
|
||||||
|
|
23
backups/2025-04-14/MyApp-1744637906.sql
Normal file
23
backups/2025-04-14/MyApp-1744637906.sql
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump
|
||||||
|
--
|
||||||
|
|
||||||
|
-- Dumped from database version 17.4
|
||||||
|
-- Dumped by pg_dump version 17.4
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET lock_timeout = 0;
|
||||||
|
SET idle_in_transaction_session_timeout = 0;
|
||||||
|
SET transaction_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = on;
|
||||||
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET xmloption = content;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET row_security = off;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump complete
|
||||||
|
--
|
||||||
|
|
23
docker-compose.yml
Normal file
23
docker-compose.yml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
services:
|
||||||
|
baktainer:
|
||||||
|
build: .
|
||||||
|
image: jamez01/baktainer:latest
|
||||||
|
container_name: baktainer
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./backups:/backups
|
||||||
|
- ./config:/config
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
environment:
|
||||||
|
- "BT_DOCKER_URL=unix:///var/run/docker.sock"
|
||||||
|
- BT_CRON=* * * * * # Backup every day at midnight
|
||||||
|
- BT_THREADS=4 # Number of threads to use for backups
|
||||||
|
- BT_BACKUP_DIR=/backups
|
||||||
|
- BT_LOG_LEVEL=info
|
||||||
|
# Enable if using SSL over tcp
|
||||||
|
#- BT_SSL = true
|
||||||
|
#- BT_CA
|
||||||
|
#- BT_CERT
|
||||||
|
#- BT_KEY
|
2
entrypoint.sh
Normal file
2
entrypoint.sh
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
exec $@
|
Loading…
Add table
Reference in a new issue