diff --git a/ci-scripts/Jenkinsfile-GitLab-Docker b/ci-scripts/Jenkinsfile-GitLab-Docker
new file mode 100644
index 0000000000000000000000000000000000000000..d1212d7306befeba08e3d8727e6c6d5fae972cdb
--- /dev/null
+++ b/ci-scripts/Jenkinsfile-GitLab-Docker
@@ -0,0 +1,270 @@
+#!/bin/groovy
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (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.openairinterface.org/?page_id=698
+ *
+ * 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.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+//-------------------------------------------------------------------------------
+// Abstraction function to send social media messages:
+// like on Slack or Mattermost
+def sendSocialMediaMessage(pipeChannel, pipeColor, pipeMessage) {
+  if (params.pipelineUsesSlack != null) {
+    if (params.pipelineUsesSlack) {
+      slackSend channel: pipeChannel, color: pipeColor, message: pipeMessage
+    }
+  }
+}
+
+// Location of the CN executor node
+def cn_ci_host = params.Host_CN_CI_Server
+
+// for lock
+def cn_ci_resource = params.DockerContainers
+def ds_tester_ci_resource = params.DsTester
+
+// Location of the 2nd CN executor
+def new_host_flag = false
+def new_host = ""
+def new_host_user = ""
+
+// Location of the CN tester
+def dsT_host_flag = false
+def dsT_host = ""
+def dsT_host_user = ""
+def dsT_host_ip_addr = ""
+
+// Flags
+def scmEvent = false
+def upstreamEvent = false
+
+// Default tags / branches  --> could be passed on by upstream job or by PR content
+def amfTag = 'develop'
+def amfBranch = 'develop'
+def smfTag = 'develop'
+def smfBranch = 'develop'
+def spgwuTag = 'develop'
+def spgwuBranch = 'develop'
+
+//-------------------------------------------------------------------------------
+// Pipeline start
+pipeline {
+  agent {
+    label cn_ci_host
+  }
+  options {
+    disableConcurrentBuilds()
+    timestamps()
+    ansiColor('xterm')
+    lock(cn_ci_resource)
+  }
+  stages {
+    stage ('Verify Parameters') {
+      steps {
+        script {
+          echo '\u2705 \u001B[32mVerify Parameters\u001B[0m'
+
+          JOB_TIMESTAMP = sh returnStdout: true, script: 'date --utc --rfc-3339=seconds | sed -e "s#+00:00##"'
+          JOB_TIMESTAMP = JOB_TIMESTAMP.trim()
+
+          if (params.Host_CN_CI_2nd_Server_Flag != null) {
+            new_host_flag = params.Host_CN_CI_2nd_Server_Flag
+            if (new_host_flag) {
+              new_host = params.Host_CN_CI_2nd_Server
+              new_host_user = params.Host_CN_CI_2nd_Server_Login
+              echo "1st Node   is ${NODE_NAME}"
+              echo "2nd Node   is ${new_host}"
+            } else {
+              echo "Node       is ${NODE_NAME}"
+            }
+          } else {
+            echo "Node       is ${NODE_NAME}"
+          }
+          if (params.DS_Tester_Server_Flag != null) {
+            dsT_host_flag = params.DS_Tester_Server_Flag
+            if (dsT_host_flag) {
+              def allParametersPresent = true
+              if (params.DS_Tester_Server_Name == null) {
+                allParametersPresent = false
+              } else {
+                dsT_host = params.DS_Tester_Server_Name
+              }
+              if (params.DS_Tester_Server_Login == null) {
+                allParametersPresent = false
+              } else {
+                dsT_host_user = params.DS_Tester_Server_Login
+              }
+              if (params.DS_Tester_Server_IP_Addr == null) {
+                allParametersPresent = false
+              } else {
+                dsT_host_ip_addr = params.DS_Tester_Server_IP_Addr
+              }
+              if (allParametersPresent) {
+                echo "DS Tester  is on ${dsT_host}"
+              } else {
+                echo "Some DS Tester parameters are missing!"
+                sh "./ci-scripts/fail.sh"
+              }
+            }
+          }
+
+          // Find out the cause of the trigger
+          for (cause in currentBuild.getBuildCauses()) {
+            if (cause.toString() ==~ /.*UpstreamCause.*/) {
+              upstreamEvent = true
+            } else {
+              scmEvent = true
+            }
+          }
+
+          if (upstreamEvent) {
+            if (params.AMF_TAG != null) {
+              amfTag = params.AMF_TAG
+              echo "Upstream Job passed AMF_TAG to use: ${amfTag}"
+            }
+            if (params.AMF_BRANCH != null) {
+              amfBranch = params.AMF_BRANCH
+              echo "Upstream Job passed AMF_BRANCH to use: ${amfBranch}"
+            }
+            if (params.SMF_TAG != null) {
+              smfTag = params.SMF_TAG
+              echo "Upstream Job passed SMF_TAG to use: ${smfTag}"
+            }
+            if (params.SMF_BRANCH != null) {
+              smfBranch = params.SMF_BRANCH
+              echo "Upstream Job passed SMF_BRANCH to use: ${smfBranch}"
+            }
+            sh "git clean -x -d -f > /dev/null 2>&1"
+            sh "mkdir -p archives DS-TEST-RESULTS"
+            if (new_host_flag) {
+              // Prepare the workspace in remote server
+              myShCmd('git clean -x -d -f > /dev/null 2>&1', new_host_flag, new_host_user, new_host)
+              myShCmd('mkdir -p archives DS-TEST-RESULTS', new_host_flag, new_host_user, new_host)
+            }
+          }
+        }
+      }
+    }
+    stage ('Deploy Whole EPC') {
+      stages {
+        stage ('Create Public Network') {
+          steps {
+            script {
+              myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=CreateNetworks', new_host_flag, new_host_user, new_host)
+            }
+          }
+        }
+        stage ('Deploy Containers') {
+          steps {
+            script {
+              sh "sleep 10"
+            }
+          }
+        }
+      }
+    }
+    stage ('Check with DS Tester') {
+      when { expression {dsT_host_flag} }
+      steps {
+        lock (ds_tester_ci_resource) {
+          script {
+            sh "sleep 10"
+          }
+        }
+      }
+    }
+    stage ('Undeploy EPC') {
+      stages {
+        stage ('Undeploy Containers') {
+          steps {
+            script {
+              // Remove the containers
+              //myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveAllContainers', new_host_flag, new_host_user, new_host)
+              sh "sleep 10"
+            }
+          }
+        }
+        stage ('Delete Public Network') {
+          steps {
+            script {
+              myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveNetworks', new_host_flag, new_host_user, new_host)
+            }
+          }
+        }
+      }
+    }
+  }
+  post {
+    always {
+      script { 
+        // Removing all containers
+        myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveAllContainers', new_host_flag, new_host_user, new_host)
+        // Removing the network
+        myShCmd('python3 ./ci-scripts/dsTestDeployTools.py --action=RemoveNetworks', new_host_flag, new_host_user, new_host)
+        // Zipping all archived log files
+        sh "zip -r -qq fed_docker_logs.zip archives DS-TEST-RESULTS/*.tar DS-TEST-RESULTS/status.txt"
+        if (fileExists('fed_docker_logs.zip')) {
+          archiveArtifacts artifacts: 'fed_docker_logs.zip'
+        }
+        if (fileExists('test_results_oai_epc.html')) {
+          archiveArtifacts artifacts: 'test_results_oai_epc.html'
+        }
+      }
+    }
+  }
+}
+
+// Functions
+
+def copyTo2ndServer(filename, flag, user, host) {
+  if (flag) {
+    sh "scp ${filename} ${user}@${host}:/tmp/CI-CN-FED"
+  }
+}
+
+def copyFrom2ndServer(filename, target, flag, user, host) {
+  if (flag) {
+    sh "scp ${user}@${host}:/tmp/CI-CN-FED/${filename} ${target}"
+  }
+}
+
+def myShCmd(cmd, flag, user, host) {
+  if (flag) {
+    sh "ssh -t -t ${user}@${host} 'cd /tmp/CI-CN-FED && ${cmd}'"
+  } else {
+    sh "${cmd}"
+  }
+}
+
+def myShCmdWithLog(cmd, logFile, flag, user, host) {
+  if (flag) {
+    sh "ssh -t -t ${user}@${host} 'export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:.:/usr/local/devsol/bin && ${cmd}' > ${logFile} 2>&1"
+  } else {
+    sh "${cmd} > ${logFile} 2>&1"
+  }
+}
+
+def myShRetCmd(cmd, flag, user, host) {
+  if (flag) {
+    ret = sh returnStdout: true, script: "ssh -t -t ${user}@${host} 'cd /tmp/CI-CN-FED && ${cmd}'"
+  } else {
+    ret = sh returnStdout: true, script: "${cmd}"
+  }
+  ret = ret.trim()
+  return ret
+}
diff --git a/ci-scripts/dsTestDeployTools.py b/ci-scripts/dsTestDeployTools.py
new file mode 100644
index 0000000000000000000000000000000000000000..7159be656a277e25edcfea1d10b7466852ec1091
--- /dev/null
+++ b/ci-scripts/dsTestDeployTools.py
@@ -0,0 +1,110 @@
+#/*
+# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+# * contributor license agreements.  See the NOTICE file distributed with
+# * this work for additional information regarding copyright ownership.
+# * The OpenAirInterface Software Alliance licenses this file to You under
+# * the OAI Public License, Version 1.1  (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.openairinterface.org/?page_id=698
+# *
+# * 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.
+# *-------------------------------------------------------------------------------
+# * For more information about the OpenAirInterface (OAI) Software Alliance:
+# *       contact@openairinterface.org
+# */
+#---------------------------------------------------------------------
+
+import os
+import re
+import sys
+import subprocess
+import time
+
+CICD_PRIVATE_NETWORK_RANGE='192.168.28.0/26'
+CICD_PUBLIC_NETWORK_RANGE='192.168.61.192/26'
+
+class deployForDsTester():
+    def __init__(self):
+        self.action = 'None'
+        self.tag = ''
+
+    def createNetworks(self):
+        # first check if already up?
+        try:
+            res = subprocess.check_output('docker network ls | egrep -c "cicd-oai-public-net|cicd-oai-private-net"', shell=True, universal_newlines=True)
+            if int(str(res.strip())) > 0:
+                self.removeNetworks()
+        except:
+            pass
+
+        subprocess_run_w_echo('docker network create --attachable --subnet ' + CICD_PUBLIC_NETWORK_RANGE + ' --ip-range ' + CICD_PUBLIC_NETWORK_RANGE + ' cicd-oai-public-net')
+        subprocess_run_w_echo('docker network create --attachable --subnet ' + CICD_PRIVATE_NETWORK_RANGE + ' --ip-range ' + CICD_PRIVATE_NETWORK_RANGE + ' cicd-oai-private-net')
+
+    def removeNetworks(self):
+        try:
+            subprocess_run_w_echo('docker network rm cicd-oai-public-net cicd-oai-private-net')
+        except:
+            pass
+
+def subprocess_run_w_echo(cmd):
+    print(cmd)
+    subprocess.run(cmd, shell=True)
+
+def Usage():
+    print('----------------------------------------------------------------------------------------------------------------------')
+    print('dsTestDeployTools.py')
+    print('   Deploy for DsTester in the pipeline.')
+    print('----------------------------------------------------------------------------------------------------------------------')
+    print('Usage: python3 dsTestDeployTools.py [options]')
+    print('  --help  Show this help.')
+    print('---------------------------------------------------------------------------------------------- Mandatory Options -----')
+    print('  --action={CreateNetworks,RemoveNetworks,...}')
+    print('-------------------------------------------------------------------------------------------------------- Options -----')
+    print('  --tag=[Image Tag in registry]')
+    print('------------------------------------------------------------------------------------------------- Actions Syntax -----')
+    print('python3 dsTestDeployTools.py --action=CreateNetworks')
+    print('python3 dsTestDeployTools.py --action=RemoveNetworks')
+
+#--------------------------------------------------------------------------------------------------------
+#
+# Start of main
+#
+#--------------------------------------------------------------------------------------------------------
+
+DFDT = deployForDsTester()
+
+argvs = sys.argv
+argc = len(argvs)
+
+while len(argvs) > 1:
+    myArgv = argvs.pop(1)
+    if re.match('^\-\-help$', myArgv, re.IGNORECASE):
+        Usage()
+        sys.exit(0)
+    elif re.match('^\-\-action=(.+)$', myArgv, re.IGNORECASE):
+        matchReg = re.match('^\-\-action=(.+)$', myArgv, re.IGNORECASE)
+        action = matchReg.group(1)
+        if action != 'CreateNetworks' and \
+           action != 'RemoveNetworks':
+            print('Unsupported Action => ' + action)
+            Usage()
+            sys.exit(-1)
+        DFDT.action = action
+    elif re.match('^\-\-tag=(.+)$', myArgv, re.IGNORECASE):
+        matchReg = re.match('^\-\-tag=(.+)$', myArgv, re.IGNORECASE)
+        DFDT.tag = matchReg.group(1)
+
+if DFDT.action == 'CreateNetworks':
+    DFDT.createNetworks()
+elif DFDT.action == 'RemoveNetworks':
+    DFDT.removeNetworks()
+
+
+sys.exit(0)
+