Use bridge network for db container

- Changed the network mode of database container to "bridge" and exposed
  the service ports.
- Use socket file to connect with the database.
- Upgrade the backup container image for postgressql.

Change-Id: Id5b119f8a474befc3a2cd6e061bbffc4ae5f7bb6
This commit is contained in:
Lingxian Kong 2021-06-18 11:30:03 +12:00
parent 6d2ab68a8a
commit b050996b9f
11 changed files with 71 additions and 11 deletions

View File

@ -18,7 +18,7 @@ WORKDIR /opt/trove/backup
RUN ./install.sh $DATASTORE RUN ./install.sh $DATASTORE
RUN apt-get update \ RUN apt-get update \
&& apt-get install $APTOPTS build-essential python3-setuptools python3-all python3-all-dev python3-pip libffi-dev libssl-dev libxml2-dev libxslt1-dev libyaml-dev \ && apt-get install $APTOPTS build-essential python3-setuptools python3-all python3-all-dev python3-pip libffi-dev libssl-dev libxml2-dev libxslt1-dev libyaml-dev libpq-dev \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/* \
&& pip3 --no-cache-dir install -U -r requirements.txt \ && pip3 --no-cache-dir install -U -r requirements.txt \

View File

@ -15,7 +15,17 @@ import psycopg2
class PostgresConnection(object): class PostgresConnection(object):
def __init__(self, user, password='', host='localhost', port=5432): def __init__(self, user, password='', host='/var/run/postgresql',
port=5432):
"""Utility class to communicate with PostgreSQL.
Connect with socket rather than IP or localhost address to avoid
manipulation of pg_hba.conf when the database is running inside
container with bridge network.
This class is consistent with PostgresConnection in
trove/guestagent/datastore/postgres/service.py
"""
self.user = user self.user = user
self.password = password self.password = password
self.host = host self.host = host

View File

@ -42,5 +42,5 @@ rsyslog:
ubuntu-cloudimage-keyring: ubuntu-cloudimage-keyring:
ureadahead: ureadahead:
uuid-runtime: uuid-runtime:
vim-tiny: vim:
vlan: vlan:

View File

@ -0,0 +1,14 @@
---
security:
- |
Changed the network mode of database container to "bridge" and exposed the
service ports. Cloud operator could adjust the iptables to restrict network
access from the database container to the outside. An example::
iptables -t filter -I DOCKER-USER 1 -d [restricted-network-range] -i docker0 ! -o docker0 -j REJECT
upgrade:
- The default value of the trove guest agent config option
``[postgresql] backup_docker_image`` is changed to
``openstacktrove/db-backup-postgresql:1.1.1``. There is nothing to do if
the option is not configured explicitly.

View File

@ -1097,7 +1097,7 @@ postgresql_opts = [
), ),
cfg.StrOpt( cfg.StrOpt(
'backup_docker_image', 'backup_docker_image',
default='openstacktrove/db-backup-postgresql:1.1.0', default='openstacktrove/db-backup-postgresql:1.1.1',
help='The docker image used for backup and restore.' help='The docker image used for backup and restore.'
), ),
cfg.BoolOpt('icmp', default=False, cfg.BoolOpt('icmp', default=False,

View File

@ -112,8 +112,10 @@ class MySqlManager(manager.Manager):
""" """
LOG.info(f"Creating backup {backup_info['id']}") LOG.info(f"Creating backup {backup_info['id']}")
with EndNotification(context): with EndNotification(context):
# Set /var/run/mysqld to allow localhost access.
volumes_mapping = { volumes_mapping = {
'/var/lib/mysql': {'bind': '/var/lib/mysql', 'mode': 'rw'}, '/var/lib/mysql': {'bind': '/var/lib/mysql', 'mode': 'rw'},
"/var/run/mysqld": {"bind": "/var/run/mysqld", "mode": "ro"},
'/tmp': {'bind': '/tmp', 'mode': 'rw'} '/tmp': {'bind': '/tmp', 'mode': 'rw'}
} }
self.app.create_backup(context, backup_info, self.app.create_backup(context, backup_info,

View File

@ -586,13 +586,20 @@ class BaseMySqlApp(service.BaseDbApp):
if extra_volumes: if extra_volumes:
volumes.update(extra_volumes) volumes.update(extra_volumes)
# Expose ports
ports = {}
tcp_ports = cfg.get_configuration_property('tcp_ports')
for port_range in tcp_ports:
for port in port_range:
ports[f'{port}/tcp'] = port
try: try:
LOG.info("Starting docker container, image: %s", image)
docker_util.start_container( docker_util.start_container(
self.docker_client, self.docker_client,
image, image,
volumes=volumes, volumes=volumes,
network_mode="host", network_mode="bridge",
ports=ports,
user=user, user=user,
environment={ environment={
"MYSQL_ROOT_PASSWORD": root_pass, "MYSQL_ROOT_PASSWORD": root_pass,

View File

@ -190,13 +190,20 @@ class PgSqlApp(service.BaseDbApp):
if extra_volumes: if extra_volumes:
volumes.update(extra_volumes) volumes.update(extra_volumes)
# Expose ports
ports = {}
tcp_ports = cfg.get_configuration_property('tcp_ports')
for port_range in tcp_ports:
for port in port_range:
ports[f'{port}/tcp'] = port
try: try:
LOG.info("Starting docker container, image: %s", image)
docker_util.start_container( docker_util.start_container(
self.docker_client, self.docker_client,
image, image,
volumes=volumes, volumes=volumes,
network_mode="host", network_mode="bridge",
ports=ports,
user=user, user=user,
environment={ environment={
"POSTGRES_PASSWORD": postgres_pass, "POSTGRES_PASSWORD": postgres_pass,
@ -727,7 +734,17 @@ class PgSqlAdmin(object):
class PostgresConnection(object): class PostgresConnection(object):
def __init__(self, user, password=None, host='localhost', port=5432): def __init__(self, user, password=None, host='/var/run/postgresql',
port=5432):
"""Utility class to communicate with PostgreSQL.
Connect with socket rather than IP or localhost address to avoid
manipulation of pg_hba.conf when the database is running inside
container with bridge network.
This class is consistent with PostgresConnection in
backup/utils/postgresql.py
"""
self.user = user self.user = user
self.password = password self.password = password
self.host = host self.host = host

View File

@ -395,6 +395,9 @@ class BaseDbApp(object):
): ):
raise exception.TroveError("Failed to stop database") raise exception.TroveError("Failed to stop database")
def start_db(self, *args, **kwargs):
pass
def start_db_with_conf_changes(self, config_contents, ds_version): def start_db_with_conf_changes(self, config_contents, ds_version):
LOG.info(f"Starting database service with new configuration and " LOG.info(f"Starting database service with new configuration and "
f"datastore version {ds_version}.") f"datastore version {ds_version}.")
@ -435,7 +438,8 @@ class BaseDbApp(object):
db_userinfo = '' db_userinfo = ''
if need_dbuser: if need_dbuser:
admin_pass = self.get_auth_password() admin_pass = self.get_auth_password()
db_userinfo = (f"--db-host=127.0.0.1 --db-user=os_admin " # Use localhost to avoid host access verification.
db_userinfo = (f"--db-host=localhost --db-user=os_admin "
f"--db-password={admin_pass}") f"--db-password={admin_pass}")
swift_metadata = ( swift_metadata = (

View File

@ -82,6 +82,7 @@ class MysqlReplicationBase(base.Replication):
volumes_mapping = { volumes_mapping = {
'/var/lib/mysql': {'bind': '/var/lib/mysql', 'mode': 'rw'}, '/var/lib/mysql': {'bind': '/var/lib/mysql', 'mode': 'rw'},
"/var/run/mysqld": {"bind": "/var/run/mysqld", "mode": "ro"},
'/tmp': {'bind': '/tmp', 'mode': 'rw'} '/tmp': {'bind': '/tmp', 'mode': 'rw'}
} }
service.create_backup(context, snapshot_info, service.create_backup(context, snapshot_info,

View File

@ -56,9 +56,14 @@ def start_container(client, image, name="database",
""" """
try: try:
container = client.containers.get(name) container = client.containers.get(name)
LOG.info(f'Starting existing container {name}')
container.start() container.start()
except docker.errors.NotFound: except docker.errors.NotFound:
LOG.warning("Failed to get container %s", name) LOG.info(
f"Creating docker container, image: {image}, "
f"volumes: {volumes}, ports: {ports}, user: {user}, "
f"network_mode: {network_mode}, environment: {environment}, "
f"command: {command}")
container = client.containers.run( container = client.containers.run(
image, image,
name=name, name=name,