我正在尝试创建一个包含一些预定义数据的Oracle DB Docker映像。该映像将在docker-compose文件中使用,以自动运行连接到Oracle DB的模块的某些单元测试。
我已经准备好了MySQL和SQL Server映像。运行这些数据库服务器,它们提供了一些简单的预定义数据库和表。
在MySQL中,此操作就像一种魅力,因为该图像已经提供了/docker-entrypoint-initdb.d
目录。我COPY
那里的脚本是在启动时执行的,我很好。
使用SQL Server会更加复杂。我在构建映像时使用/opt/mssql/bin/sqlservr
启动SQL Server。当SQL Server启动时,shell脚本调用/opt/mssql-tools/bin/sqlcmd
来运行一些脚本来创建我要提供的数据库和表。也应该很好。
使用Oracle DB,似乎无法创建已经包含一些数据的映像。
这是我目前正在尝试的:
FROM store/oracle/database-enterprise:12.2.0.1-slim
ENV ORACLE_SYS_USER=sys
ENV ORACLE_SYS_PASSWORD=Oradoc_db1
ENV ORACLE_PDB=ORCLPDB1
ENV ORACLE_DATABASE=test
ENV ORACLE_USER=test
ENV ORACLE_PASSWORD=test
USER root
RUN mkdir -p /usr/local/src/oracle
WORKDIR /usr/local/src/oracle
COPY ./docker/wait-for-it.sh /usr/local/src/oracle
COPY ./docker/oracle/start-import.sh /usr/local/src/oracle
COPY ./docker/oracle/import-data.sh /usr/local/src/oracle
COPY ./docker/oracle/create-database.sql /usr/local/src/oracle
COPY ./docker/oracle/testdata.sql /usr/local/src/oracle
RUN chmod +x /usr/local/src/oracle/wait-for-it.sh
RUN chmod +x /usr/local/src/oracle/prepare-import.sh
RUN chmod +x /usr/local/src/oracle/start-import.sh
RUN chmod +x /usr/local/src/oracle/import-data.sh
RUN chown -R oracle:dba /usr/local/src/oracle
USER oracle
RUN ./start-import.sh
ENTRYPOINT /home/oracle/setup/dockerInit.sh
start-import.sh:
#!/bin/sh
# Start the server. From its source it seems that Oracle prefers bash.
/bin/bash /home/oracle/setup/dockerInit.sh &
./wait-for-it.sh "localhost:1521" -t 300 -- ./import-data.sh
kill %1
wait
import-data.sh:
#!/bin/bash
/u01/app/oracle/product/12.2.0/dbhome_1/bin/sqlplus -s $ORACLE_SYS_USER/$ORACLE_SYS_PASSWORD AS SYSDBA << SQL
@/usr/local/src/oracle/create-database.sql
exit;
SQL
/u01/app/oracle/product/12.2.0/dbhome_1/bin/sqlplus -s $ORACLE_USER/$ORACLE_PASSWORD << SQL
@/usr/local/src/oracle/testdata.sql
exit;
SQL
我在这里跳过了两个SQL文件。在普通的Oracle DB Docker映像中运行它们可以正常运行。关于sqlplus
的呼叫,我已经尝试过其他一些呼叫,例如sqlplus ... @script.sql
,但没有一个起作用。
阅读脚本,我希望在映像创建过程中启动Oracle DB服务器,并且一旦启动,sqlplus
调用就会创建我想要的数据库结构。但是我要么得到要么
Done ! The database is ready for use .
# ===========================================================================
# == Add below entries to your tnsnames.ora to access this database server ==
# ====================== from external host =================================
ORCLCDB=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<ip-address>)(PORT=<port>))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCLCDB.localdomain)))
ORCLPDB1=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<ip-address>)(PORT=<port>))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=ORCLPDB1.localdomain)))
#
#ip-address : IP address of the host where the container is running.
#port : Host Port that is mapped to the port 1521 of the container.
#
# The mapped port can be obtained from running "docker port <container-id>"
# ===========================================================================
ORCLPDB1(3):Database Characterset for ORCLPDB1 is WE8DEC
ORCLPDB1(3):Opatch validation is skipped for PDB ORCLPDB1 (con_id=0)
2019-04-15T12:44:22.591697+00:00
ORCLPDB1(3):Opening pdb with no Resource Manager plan active
Pluggable database ORCLPDB1 opened read write
Completed: alter pluggable database ORCLPDB1 open
alter pluggable database all save state
Completed: alter pluggable database all save state
2019-04-15T12:44:22.844748+00:00
ALTER SYSTEM SET encrypt_new_tablespaces='DDL' SCOPE=BOTH;
wait-for-it.sh: localhost:1521 is available after 99 seconds
ERROR:
ORA-03113: end-of-file on communication channel
Process ID: 0
Session ID: 0 Serial number: 0
SP2-0306: Invalid option.
Usage: CONN[ECT] [{logon|/|proxy} [AS {SYSDBA|SYSOPER|SYSASM|SYSBACKUP|SYSDG|SYSKM|SYSRAC}] [edition=value]]
where <logon> ::= <username>[/<password>][@<connect_identifier>]
<proxy> ::= <proxyuser>[<username>][/<password>][@<connect_identifier>]
SP2-0306: Invalid option.
Usage: CONN[ECT] [{logon|/|proxy} [AS {SYSDBA|SYSOPER|SYSASM|SYSBACKUP|SYSDG|SYSKM|SYSRAC}] [edition=value]]
where <logon> ::= <username>[/<password>][@<connect_identifier>]
<proxy> ::= <proxyuser>[<username>][/<password>][@<connect_identifier>]
SP2-0157: unable to CONNECT to ORACLE after 3 attempts, exiting SQL*Plus
ERROR:
ORA-01034: ORACLE not available
ORA-27101: shared memory realm does not exist
Linux-x86_64 Error: 2: No such file or directory
Additional information: 3701
Additional information: 1724833639
如果有人有一个主意,那就太好了。是的,我将尝试使用卷运行超薄图像。然后创建表并在我的docker-compose环境中使用生成的卷。
答案 0 :(得分:0)
没有那种方法可以工作。我决定运行一个官方映像,修改数据库,并使用修改后的容器创建自己的映像。
答案 1 :(得分:0)
我现在花了整整一周的时间来创建一个docker映像,该映像提供了一个立即运行的oracle DB ,其中填充了一些用户表和数据。简而言之:就“立即”而言,我没有成功,但是我可以构建一个映像(通过maven docker插件自动化),该映像提供了一个最初填充有所需用户,模式和一些数据的数据库。
一些我没有成功的缺点:
我将描述我的方法和遇到的障碍,也许它可以为其他人进行更多调查提供启发。
这是我的Dockerfile:
FROM store/oracle/database-enterprise:12.2.0.1-slim
# mounted persistent volume
ENV MOUNTED_VOLUME /mnt/host
# Copy the data folder which is originally located in the defined VOLUME of the base image (/ORCL)
# into an own folder (~/MYORCL) by manipulating one of the install scripts.
# At the end of the DB install the created links are replaced by new ones.
RUN sed -i '101i cat $CONFIG_LOG' /home/oracle/setup/setupDB.sh
RUN cat /home/oracle/setup/setupDB.sh
RUN sed -i '218i cp -r /ORCL/* ~/MYORCL' /home/oracle/setup/configDBora.sh
RUN sed -i '218i mkdir -p ~/MYORCL' /home/oracle/setup/configDBora.sh
RUN cat /home/oracle/setup/configDBora.sh
# setup the DB
RUN /bin/bash /home/oracle/setup/setupDB.sh
# recreate the symbolic links to the new locations in ~/MYORCL
RUN unlink $ORACLE_HOME/dbs \
&& ln -s ~/MYORCL/$ORACLE_HOME/dbs $ORACLE_HOME/dbs
RUN unlink /u01/app/oracle/diag \
&& ln -s ~/MYORCL/u01/app/oracle/diag /u01/app/oracle/diag
RUN unlink /u02/app/oracle/audit \
&& ln -s ~/MYORCL/u02/app/oracle/audit /u02/app/oracle/audit
RUN unlink /u02/app/oracle/oradata \
&& ln -s ~/MYORCL/u02/app/oracle/oradata /u02/app/oracle/oradata
RUN unlink /u03/app/oracle/fast_recovery_area\
&& ln -s ~/MYORCL/u03/app/oracle/fast_recovery_area /u03/app/oracle/fast_recovery_area
RUN unlink /u04/app/oracle/redo \
&& ln -s ~/MYORCL/u04/app/oracle/redo /u04/app/oracle/redo
ENV RESOURCE_DIR eas-dist/docker/oracle-db/resources
ENV SQL_DIR $RESOURCE_DIR/sql
ENV BIN_DIR $RESOURCE_DIR/bin
ENV SETUP_BIN_DIR /home/oracle/setup
ENV SETUP_SQL_DIR /home/oracle/setup/sql
RUN mkdir $SETUP_SQL_DIR \
&& chown oracle:oinstall $SETUP_SQL_DIR \
&& chmod 755 $SETUP_SQL_DIR
# copy our EAS init scripts
COPY --chown=oracle:oinstall $BIN_DIR/createEasDb.sh $SETUP_BIN_DIR/createEasDb.sh
RUN chmod 755 $SETUP_BIN_DIR/createEasDb.sh
COPY --chown=oracle:oinstall eas-common/src/main/sql/createDB/001_Create_EAS_User.sql $SETUP_SQL_DIR/001_Create_EAS_User.sql
RUN chmod 755 $SETUP_SQL_DIR/001_Create_EAS_User.sql \
&& sed -i 's/\x0D$//' $SETUP_SQL_DIR/001_Create_EAS_User.sql
COPY --chown=oracle:oinstall eas-common/src/main/sql/createDB/002_Create_EAS_Tables.sql $SETUP_SQL_DIR/002_Create_EAS_Tables.sql
RUN chmod 755 $SETUP_SQL_DIR/002_Create_EAS_Tables.sql \
&& sed -i 's/\x0D$//' $SETUP_SQL_DIR/002_Create_EAS_Tables.sql
COPY --chown=oracle:oinstall eas-common/src/main/sql/createDB/003_EAS_InitialFill.sql $SETUP_SQL_DIR/003_EAS_InitialFill.sql
RUN chmod 755 $SETUP_SQL_DIR/003_EAS_InitialFill.sql \
&& sed -i 's/\x0D$//' $SETUP_SQL_DIR/003_EAS_InitialFill.sql
ENV PATH "$PATH:/u01/app/oracle/product/12.2.0/dbhome_1/bin"
VOLUME $MOUNTED_VOLUME
# copy our entrypoint startup script
COPY --chown=oracle:oinstall $BIN_DIR/startup.sh $SETUP_BIN_DIR/startup.sh
RUN chmod 755 $SETUP_BIN_DIR/startup.sh
# start the DB
ENTRYPOINT exec /bin/bash /home/oracle/setup/startup.sh
请注意,我不是直接通过RUN命令而是通过操纵原始设置脚本(RUN sed ...)来执行复制操作(/ ORCL->〜/ MYORCL),以便在docker RUN setupDB中执行.sh步骤。 Oracle会初始化已声明的VOLUME / ORCL中的所有数据文件,由于尚未装入永久主机文件夹,该文件在此RUN步骤后消失了,因此所有初始化将丢失。
还有我的startup.sh脚本(注意:我留下了一些不成功的尝试作为注释掉的代码,以及为什么它不起作用的注释):
#!/bin/sh
#
# Note: this is a copy of the file /home/oracle/setup/dockerInit.sh of the docker
# image store/oracle/database-enterprise:12.2.0.1-slim
# The original calls setupDB.sh on the first start. Our Dockerfile has already done that.
# Thus we only need to startup the DB, init our users, schema and initial data. Finally the
# rest of the original script is used to gracefully shutdown (term_handler)
# basic parameters
LOG_DIR=/home/oracle/setup/log
SETUP_DIR=/home/oracle/setup
if [ ! -d $LOG_DIR ]
then
mkdir $LOG_DIR
chmod 775 $LOG_DIR
chown oracle:oinstall $LOG_DIR
fi
# logfile
INIT_LOG=$LOG_DIR/dockerInit.log
echo `date` >> $INIT_LOG
echo "Executing script ${0}"
echo "Executing script ${0}" >> $INIT_LOG
echo ORACLE_HOME: $ORACLE_HOME
echo ORACLE_HOME: $ORACLE_HOME >> $INIT_LOG
# check setup path
if [ ! -d $SETUP_DIR ]
then
echo "ERROR : setup files are not found"
echo "ERROR : setup files are not found" >> $INIT_LOG
echo "" >> $INIT_LOG
exit 1
fi
MOUNT_DIR=/mnt/host
EAS_USER_CREATED_MARKER_FILE=$MOUNT_DIR/eas_user_created.txt
MOUNT_DIR_DATA_NAME=datafiles
MOUNT_DIR_DATA=$MOUNT_DIR/$MOUNT_DIR_DATA_NAME
# export it in order to be used in sub scripts (e.g. for creating the tablespaces)
export MOUNT_DIR_DATA
# TODO: All attempts to persist the initialized DB failed until now
# Main reason: Not all files of the changeable data can be copied to the mounted VOLUME. See remark below
# Thus the EAS2 user disappears after a restart of the image (note: restarting a stopped container preserves
# the EAS2 user and all changed data).
# Although the eas schema is created using the tablespaces on the mounted VOLUME: Inspecting a table's
# "Speicherung" in SQLDeveloper shows that the table is not assigned to a tablespace.
# We have to find a way how all necessary changeable data can be mounted to VOLUME. Oracle originally installs
# all these files in the declared VOLUME /ORCL (see manipulations in our Dockerfile, which copies all these
# files into the unmounted folder ~/MYORCL and adapts the symbolic links to there).
# Current state: It is not possible to restart a stopped container. Always start a new fresh container by
# running the image which will provide a working eas DB (user and schema created, initially filled). That's
# why we delete here all data found in the mounted folder:
echo "content of mounted volume /mnt/host"
ls -la $MOUNT_DIR
if [ -f $EAS_USER_CREATED_MARKER_FILE ]
then
echo "Not the first time this image is starting up. Found files in mounted VOLUME. Going to delete them."
echo "Not the first time this image is starting up. Found files in mounted VOLUME. Going to delete them." >> $INIT_LOG
rm $EAS_USER_CREATED_MARKER_FILE
rm -R $MOUNT_DIR_DATA
ls -la $MOUNT_DIR
fi
# startup the DB
echo `date` "Start up Oracle Database"
echo `date` "Start up Oracle Database" >> $INIT_LOG
/bin/bash $SETUP_DIR/startupDB.sh 2>&1
echo `date` "startup done. Going initialize EAS"
echo `date` "startup done. Going initialize EAS" >> $INIT_LOG
USER=`whoami`
echo USER: $USER
# Initialize EAS user and schema (if not yet done)
if [ ! -f $EAS_USER_CREATED_MARKER_FILE ]
then
echo "Virgin DB found. Create EAS user and schema"
echo "Virgin DB found. Create EAS user and schema" >> $INIT_LOG
# check whether it is the first time this container is up
# if it is the first time, copy the ~/MYORCL to /mnt/host/MYORCL
# TODO: Does not work. Reasons:
# - if the data files are mounted in a VOLUME then sys as sysdba cannot connect anymore!
# - not all files/dirs of ~/MYORCL can be copied. Some files are symbolic links which cannot be copied
# to a windows mapped VOLUME
# if [ ! -d $MOUNT_DIR_DATA/$ORACLE_HOME/dbs ]
# then
# echo "First time start up. Copy data folder to mounted volume"
# echo "First time start up. Copy data folder to mounted volume" >> $INIT_LOG
# cp -r ~/MYORCL/u01 $MOUNT_DIR_DATA/u01
# # note: u02 contains symbolic links which cannot be copied to mounted volume
# #cp -r ~/MYORCL/u02 $MOUNT_DIR_DATA/u02
# cp -r ~/MYORCL/u03 $MOUNT_DIR_DATA/u03
# cp -r ~/MYORCL/u04 $MOUNT_DIR_DATA/u04
# ls -la $MOUNT_DIR_DATA
#
# echo "Re-create the oracle links"
# echo "Re-create the oracle links" >> $INIT_LOG
# unlink $ORACLE_HOME/dbs
# ln -s $MOUNT_DIR_DATA/$ORACLE_HOME/dbs $ORACLE_HOME/dbs
# unlink /u01/app/oracle/diag
# ln -s $MOUNT_DIR_DATA/u01/app/oracle/diag /u01/app/oracle/diag
# # note: omit u02, see above
# # unlink /u02/app/oracle/audit
# # ln -s $MOUNT_DIR_DATA/u02/app/oracle/audit /u02/app/oracle/audit
# # unlink /u02/app/oracle/oradata
# # ln -s $MOUNT_DIR_DATA/u02/app/oracle/oradata /u02/app/oracle/oradata
# unlink /u03/app/oracle/fast_recovery_area
# ln -s $MOUNT_DIR_DATA/u03/app/oracle/fast_recovery_area /u03/app/oracle/fast_recovery_area
# unlink /u04/app/oracle/redo
# ln -s $MOUNT_DIR_DATA/u04/app/oracle/redo /u04/app/oracle/redo
# fi
# ensure that /mnt/host/MYORCL exists
if [ ! -d $MOUNT_DIR_DATA ]
then
echo "Creating ${MOUNT_DIR_DATA}"
echo "Creating ${MOUNT_DIR_DATA}" >> $INIT_LOG
mkdir -p $MOUNT_DIR_DATA
chmod 777 $MOUNT_DIR_DATA
fi
/bin/bash $SETUP_DIR/createEasDb.sh 2>&1
# a log-in as EAS2 user does not work until the DB is in state "healthy"
# but following attempt does not work for waiting on the healthy status (healthcheck.sh
# immediatly returns 0)
# $SETUP_DIR/healthcheck.sh
# HEALTHY=$?
# echo HEALTHY: $HEALTHY
# until [ ${HEALTHY} -eq 0 ]; do
# echo "DB not yet 'healthy', going to wait 1 second"
# sleep 1s
# $SETUP_DIR/healthcheck.sh
# HEALTHY=$?
# echo HEALTHY: $HEALTHY
# done
# echo "going to wait 10 minutes"
# sleep 10m
# /bin/bash $SETUP_DIR/createEasSchema.sh 2>&1
echo "Creating marker file ${EAS_USER_CREATED_MARKER_FILE}"
echo "Creating marker file ${EAS_USER_CREATED_MARKER_FILE}" >> $INIT_LOG
touch $EAS_USER_CREATED_MARKER_FILE
echo "#### This file is automatically generated, please do not edit ####" >> $EAS_USER_CREATED_MARKER_FILE
echo "#### Its presence indicates that the EAS user and schema is already created ####" >> $EAS_USER_CREATED_MARKER_FILE
fi
echo `date` "initialize EAS done. Going to wait for the SIGTERM"
echo `date` "initialize EAS done. Going to wait for the SIGTERM" >> $INIT_LOG
# basic parameters
BASH_RC=/home/oracle/.bashrc
source ${BASH_RC}
# Define SIGTERM-handler for graceful shutdown
term_handler() {
if [ $childPID -ne 0 ]; then
echo going to call shutDB.sh
/bin/bash $SETUP_DIR/shutDB.sh
fi
exit 143; # 128 + 15 -- SIGTERM
}
# setup SIGTERM Handler
trap 'kill ${!}; term_handler' SIGTERM
echo Trap will kill ${!} and call term_handler
# keep container runing
ALERT_LOG=/u01/app/oracle/diag/rdbms/${ORACLE_SID,,}/${ORACLE_SID}/trace/alert_${ORACLE_SID}.log
tail -f $ALERT_LOG &
childPID=$!
echo Waiting for childPID $childPID
wait $childPID
# end
最后是我特定的DB-Setup脚本:
#!/bin/sh
#
# Creates the EAS users, all tables and indices and performs an initial fill
echo Executing script $0
LOG_DIR=/home/oracle/setup/log
CREATE_EAS_USER_LOG=$LOG_DIR/createEasDB.log
CREATE_USER_SCRIPT=$SETUP_SQL_DIR/001_Create_EAS_User.sql
CREATE_SCHEMA_SCRIPT=$SETUP_SQL_DIR/002_Create_EAS_Tables.sql
INITIAL_FILL_SCRIPT=$SETUP_SQL_DIR/003_EAS_InitialFill.sql
TABLESPACE_DATA=EAS_DATA
TABLESPACE_INDEX=EAS_INDEX
touch $CREATE_EAS_USER_LOG
function log {
echo `date` $@
echo `date` $@ >> $CREATE_EAS_USER_LOG
}
# basic parameters (copied from oracle script startupDB.sh)
# to ensure all environment variables are set correctly
BASH_RC=/home/oracle/.bashrc
source ${BASH_RC}
log "MOUNT_DIR_DATA : ${MOUNT_DIR_DATA}"
log "CREATE_EAS_USER_LOG : ${CREATE_EAS_USER_LOG}"
log "TABLESPACE_DATA : ${TABLESPACE_DATA}"
log "TABLESPACE_INDEX : ${TABLESPACE_INDEX}"
log "CREATE_USER_SCRIPT : ${CREATE_USER_SCRIPT}}"
log "CREATE_SCHEMA_SCRIPT: ${CREATE_SCHEMA_SCRIPT}"
log "INITIAL_FILL_SCRIPT : ${INITIAL_FILL_SCRIPT}"
# create tablespaces, eas users, schema and initial fill
sqlplus / as sysdba 2>&1 <<EOF
spool ${CREATE_EAS_USER_LOG};
alter session set container = ORCLPDB1;
CREATE TABLESPACE $TABLESPACE_DATA DATAFILE '${MOUNT_DIR_DATA}/eas_data.dbf' SIZE 100m reuse autoextend on maxsize unlimited;
CREATE TABLESPACE $TABLESPACE_INDEX DATAFILE '${MOUNT_DIR_DATA}/eas_index.dbf' SIZE 10m reuse autoextend on maxsize unlimited;
start $CREATE_USER_SCRIPT xxx-pw1 xxx-pw2 $TABLESPACE_DATA $TABLESPACE_INDEX;
start $CREATE_SCHEMA_SCRIPT $TABLESPACE_DATA $TABLESPACE_INDEX;
start $INITIAL_FILL_SCRIPT $TABLESPACE_DATA $TABLESPACE_INDEX;
spool off;
exit;
EOF
# end
基本上,我只想以sys用户身份运行第一个脚本(001_Create_EAS_User.sql),而以新用户EAS2运行其他脚本。但是-就像说的-EAS2用户只能在大约1.5分钟后访问(“ docker ps”显示“健康”时)。我没有设法在脚本中等待(请参阅注释的代码和startup.sh中的注释)。
容器停止后不会关闭
我还尝试不在入口点脚本的末尾调用shutdown(并且-类似地-仅在第一个映像启动时调用startupDB.sh),这样的想法是重新启动映像或容器将立即提供运行初始化的数据库没有启动延迟,但是没有成功。 oracle实例无法在这样停止的容器中生存。我不知道为什么。