Good choice, I'm already using gitlab in our company, with closed sources. In our process, I even deploy to our own windows server. Our application on Angular 2.

it is our gitlab-ci.yml, I've removed deploy stage.

image: node:5

stages:
  - test
  - build

cache:
  key: "$CI_PROJECT_NAME/$CI_BUILD_REF_NAME"
  paths:
    - ./node_modules/

before_script:
  - export PATH=$PATH:./node_modules/.bin/
  - npm install

tslint_job:
  stage: test
  tags:
    - linux
    - docker
  script:
    - ng lint

test_job:
  stage: test
  tags:
    - linux
    - docker
  script:
    - karma start --browsers PhantomJS --single-run

build_job:
  stage: build
  tags:
    - linux
    - docker
  artifacts:
    expire_in: 1 week
    paths:
      - dist/*
  script:
    - ng build --aot-prod --bh "./"

Counts only lines which appear in the final "INT" code.  If you working with MAC code, you may open INT by pressing Ctrl+Shift+V in the Studio. And then you can go to this needed line wit dialog called by Ctrl+Shift+G, Where you should put 'label+line' or just '+line'. If you Studio says, that no other sources, you should check flag "Keep Generated Source Code" and add compiler flag "k" in the Studio options and recompile your routine.

Before doing such task, you should know a bit more about technologies which you going to use.
PDF - it is a binary format, so, you can't just copy text from PDF. Some of the files may contain a text, some just a picture with text.
And to get plain text from PDF, you have to use some third party OCR software. One of the leaders is ABBYY FineReader it is proprietary, but if you need you can find some products for free.

When you want to use Ensemble on Docker, it means that you need some integration with some external services. When you have to connect to some external services, no need any extra actions. But when you should use some shared folder, or some own internal services, which will be used by others, you have to expose some TCP ports, or volumes, and do some changes in a running process for this container. But you can use some network settings for the container, and in this case, Ensemble will be as a usual machine in your network, and you don't need to change any settings when you have to add some new internal service into Ensemble Production.
Windows also supports Docker but from version Server 2016. Windows also supports windows containers, but I don't know yet, is it supported to run windows version of Ensemble or not.

What you need to start your first Ensemble container within Ensemble application. The easiest way is to define some %Installer Manifest. When you can create a new database, load and compile your code, do some changes in an Ensemble settings.
There are some different examples of Dockerfile.
Quite simple, with only Ensemble. Or even with Apache inside, for some web application.

You can also look at this example of Dockerfile

### Cache ###
FROM tutum/centos:latest

MAINTAINER Dmitry Maslennikov <Dmitry.Maslennikov@csystem.cz>

# update OS + dependencies & run Caché silent instal
RUN yum -y update \
 && yum -y install which tar hostname net-tools wget \
 && yum -y clean all \ 
 && ln -sf /etc/locatime /usr/share/zoneinfo/Europe/Prague

ARG WRC_USERNAME
ARG WRC_PASSWORD
ARG cache=ensemble-2016.2.1.803.0
ARG globals8k=512
ARG routines=32
ARG locksiz=117964800

ENV TMP_INSTALL_DIR=/tmp/distrib

# vars for Caché silent install
ENV ISC_PACKAGE_INSTANCENAME="ENSEMBLE" \
    ISC_PACKAGE_INSTALLDIR="/opt/ensemble/" \
    ISC_PACKAGE_UNICODE="Y" \
    ISC_PACKAGE_CLIENT_COMPONENTS="" \

# vars for install our application     
    ISC_INSTALLER_MANIFEST=${TMP_INSTALL_DIR}/Installer.cls \
    ISC_INSTALLER_LOGFILE=installer_log \
    ISC_INSTALLER_LOGLEVEL=3 \
    ISC_INSTALLER_PARAMETERS="routines=$routines,locksiz=$locksiz,globals8k=$globals8k"

# set-up and install Caché from distrib_tmp dir 
WORKDIR ${TMP_INSTALL_DIR}

# our application installer
COPY Installer.cls .
# custom installation manifest 
COPY custom_install-manifest.isc ./$cache-lnxrhx64/package/custom_install/manifest.isc 
# license file
COPY cache.key $ISC_PACKAGE_INSTALLDIR/mgr/

# cache distributive
RUN wget -qO /dev/null --keep-session-cookies --save-cookies /dev/stdout --post-data="UserName=$WRC_USERNAME&Password=$WRC_PASSWORD" 'https://login.intersystems.com/login/SSO.UI.Login.cls?referrer=https%253A//wrc.intersystems.com/wrc/login.csp' \
 | wget -O - --load-cookies /dev/stdin "https://wrc.intersystems.com/wrc/WRC.StreamServer.cls?FILE=/wrc/distrib/$cache-lnxrhx64.tar.gz" \
 | tar xvfzC - . \
 && chmod +r ./$cache-lnxrhx64/package/custom_install/manifest.isc \
 && ./$cache-lnxrhx64/cinstall_silent custom_install \
 && cat $ISC_PACKAGE_INSTALLDIR/mgr/cconsole.log \
 && cat $ISC_PACKAGE_INSTALLDIR/mgr/installer_log \
 && ccontrol stop $ISC_PACKAGE_INSTANCENAME quietly \
 && rm -rf $TMP_INSTALL_DIR

# Caché container main process PID 1 (https://github.com/zrml/ccontainermain)
RUN curl -L https://github.com/daimor/ccontainermain/releases/download/0.1/ccontainermain -o /ccontainermain \
 && chmod +x /ccontainermain

# TCP sockets that can be accessed if user wants to (see 'docker run -p' flag)
EXPOSE 57772 1972 22

ENTRYPOINT ["/ccontainermain", "-cconsole", "-i", "ensemble"]

And installer manifest, with just some settings.

Class Temp.Installer 
{

XData setup [ XMLNamespace = INSTALLER ]
{
<Manifest>
  <If Condition='+"${routines}"=0'>
    <Var Name="routines" Value="32"/>
  </If>
  <If Condition='+"${globals8k}"=0'>
    <Var Name="globals8k" Value="256"/>
  </If>
  <If Condition='+"${locksiz}"=0'>
    <Var Name="locksiz" Value="1179648"/>
  </If>

  <SystemSetting 
    Name="Config.config.routines"
    Value="${routines}"/>

  <SystemSetting 
    Name="Config.config.globals8kb"
    Value="${globals8k}"/>

  <SystemSetting 
    Name="Config.config.locksiz"
    Value="${locksiz}"/>

</Manifest>
}

ClassMethod setup(
    ByRef pVars, 
    pLogLevel As %Integer = 3, 
    pInstaller As %Installer.Installer, 
    pLogger As %Installer.AbstractLogger
  ) As %Status [ CodeMode = objectgenerator, Internal ]
{
    do %code.WriteLine($char(9)_"set pVars(""CURRENTCLASS"")="""_%classname_"""")
    do %code.WriteLine($char(9)_"set pVars(""CURRENTNS"")="""_$namespace_"""")
  #; Let our XGL document generate code for this method. 
  Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "setup")
}

}

In this example, Ensemble distributive will be downloaded directly from the WRC.

to build this image

docker build -t ensemble --build-arg WRC_USERNAME=******* --build-arg WRC_PASSWORD=******* .

and to run the container from this image

docker run -p 57772:57772 ensemble

Most companies doing their backup over the network. It depends on how big your database, and you should estimate,  how quickly it will be in your case theoretical and in practice. Unfortunately, on some old versions of Caché, in some cases there are some lack of performance and backup may work not so fast as expected. We had such issue with 2012.2.

And a little hint, to do backup over the network, Caché instance should have an access. And if your Caché works on Windows, you should change user in settings for Caché Service, to some domain user, which will have access to write.

You got this error because you tried to use ODBC connection, but you say that you have JDBC connection. You should understand that it is different, with different ways to connect.

If you really use JDBC, you can create the new connection to the Oracle database, with a help from this article in the documentation. And with a code something like this, you can retrieve needed data from that server.

 #dim %JDBCGateway As %Net.Remote.Java.JDBCGateway
  set conn=$system.SQLGateway.GetJDBCConnection("cache2samples")
  if conn'="" {
    set cmd = "SELECT top 10 id,ssn,name,age,dob FROM Sample.Person"
    set st = %JDBCGateway.prepareStatement(conn,cmd)
    set %JDBCGateway.StatementCache(conn) = st
    set query = %JDBCGateway.execQuery(st)
    set columns=%JDBCGateway.getColumnCount(st)
    write !
    set pos=0
    for i=1:1:columns {
      set name=%JDBCGateway.getColumnName(st,i)
      set size=%JDBCGateway.getColumnDisplaySize(st,i)
      set pos(i)=pos
      set pos=pos+size+1
      write name,?pos
    }
    while %JDBCGateway.next(st) {
      write !
      for i=1:1:columns {
        write ?pos(i),%JDBCGateway.getString(st,i) 
      }
    }
  }

In password security most valuable is entropy.

And a bit of humor about it.

It means, that even if you have a quite hard pattern for the password, but some password will not be strong enough.

On the internet, you can find some online calculators, for the password, when you can check how different symbols change difficulty. For example http://www.passwordmeter.com/