From d8f1573dfd16ce7f271ff3c82abc9724ee1d5c80 Mon Sep 17 00:00:00 2001 From: Stephen C Phillips <steve@scphillips.com> Date: Fri, 3 Apr 2020 17:07:31 +0100 Subject: [PATCH] WIP: deployment working perhaps, host:8080 --- Vagrantfile | 2 +- docker/Dockerfile_base | 1 + docker/Dockerfile_deployment | 9 +-- docker/deploy.sh | 106 +++++++++++++++++++++++++++++++++++ vagrant/base.sh | 106 ++++++++++++++++++++++++++--------- 5 files changed, 191 insertions(+), 33 deletions(-) create mode 100644 docker/deploy.sh diff --git a/Vagrantfile b/Vagrantfile index e0013d5..dc793cc 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -6,7 +6,7 @@ Vagrant.configure("2") do |config| config.vm.box = "ubuntu/bionic64" config.vm.hostname = hostname - config.vm.network "forwarded_port", guest: 8001, host: 8001 + config.vm.network "forwarded_port", guest: 8080, host: 8080 config.vm.synced_folder ".", "/vagrant" #config.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".git/" diff --git a/docker/Dockerfile_base b/docker/Dockerfile_base index 2d7a290..8eaa82e 100644 --- a/docker/Dockerfile_base +++ b/docker/Dockerfile_base @@ -1,3 +1,4 @@ FROM alpine:latest +# apk is Alpine's apt-get equivalent RUN apk update && apk add curl git openjdk8 gradle nodejs libffi-dev openssl-dev git-lfs \ No newline at end of file diff --git a/docker/Dockerfile_deployment b/docker/Dockerfile_deployment index de36606..2274fd6 100644 --- a/docker/Dockerfile_deployment +++ b/docker/Dockerfile_deployment @@ -1,21 +1,16 @@ ARG GCP_HOST - ARG GCP_PROJECT_ID FROM $GCP_HOST/$GCP_PROJECT_ID/ssm-base:alpine -MAINTAINER NAJD - COPY ./build ./build - COPY ./docker/deploy.sh . +# RUN lines are executed when the image is built RUN mv ./build/libs/*.war ./ - RUN rm -rf /build/* - RUN ls -l - RUN chmod +x ./deploy.sh +# CMD is run when a container (created from the image) boots CMD ./deploy.sh diff --git a/docker/deploy.sh b/docker/deploy.sh new file mode 100644 index 0000000..50572c5 --- /dev/null +++ b/docker/deploy.sh @@ -0,0 +1,106 @@ +apk update +apk upgrade + +#Setting Java OpenJDK runtime environment variables +export JAVA_HOME="/usr/lib/jvm/java-1.8-openjdk/" +export JAVA_OPTS="-Xmx2G" +export CATALINA_HOME="/var/lib/tomcat" +export CATALINA_BASE="/var/lib/tomcat" + +if [ ! -d "/var/lib/tomcat" ]; then +echo "First boot of container: downloading tomcat!" + +#Download tomcat 7.0.96 +curl -s -o "tomcat7.tar.gz" https://archive.apache.org/dist/tomcat/tomcat-7/v7.0.96/bin/apache-tomcat-7.0.96.tar.gz +echo "Tomcat7 downloaded!" + +#probably can be uninstalled to save space +#apk del curl + +#Make tomcat folder and unpack tomcat executable +mv /tomcat7.tar.gz /var/lib/ +cd /var/lib/ +mkdir tomcat +tar -C tomcat -xzf "tomcat7.tar.gz" --strip-components=1 +rm tomcat7.tar.gz +echo "Unpacked Tomcat7!" + +#Make JENA folder and unpack .war +cd tomcat +mkdir jena-tdb +cd webapps +mkdir system-modeller +mv /*.war ./system-modeller/ +cd system-modeller/ +unzip system-modeller-*.war + +#Setting MongoDB connection variables +cd WEB-INF/classes/ +sed -i 's/spring.data.mongodb.host=localhost/spring.data.mongodb.host='"$MONGO_MONGODB_SERVICE_HOST"'/g' application.properties +sed -i 's/# Mongo/# Mongo\nspring.data.mongodb.username=root\nspring.data.mongodb.password='"$MONGODB_ROOT_PASSWORD"'\nspring.data.mongodb.authentication-database=admin/g' application.properties + +cd /var/lib/tomcat/bin +./catalina.sh start + +echo "Waiting for tomcat7 to start" +until [ "`curl --silent --show-error --connect-timeout 1 -I http://localhost:8080 | grep 'Coyote'`" != "" ]; +do + echo "Waiting for tomcat7 to start..." + sleep 5 +done + +echo "Tomcat7 started!" +echo "Setting reset.on.start to false for subsequent reboots..." + +cd /var/lib/tomcat/webapps/system-modeller/WEB-INF/classes/ +sed -i 's/reset.on.start=true/reset.on.start=false/g' application.properties +sed -i 's/reset.on.start=true/reset.on.start=false/g' application-production.properties + +echo "Restarting tomcat7" + +cd /var/lib/tomcat/bin +./catalina.sh stop + +sleep 5 + +else +echo "Tomcat already installed: the container must be restarting?" + +fi + +if test -n "$(find / -maxdepth 1 -name '*.war' -print -quit)" +then + echo "This appears to be an upgrade as system-modeller.war is present at root!" + cd /var/lib/tomcat/webapps + rm -rf system-modeller + mkdir system-modeller + mv /*.war ./system-modeller/ + cd system-modeller/ + unzip system-modeller-*.war + + #Setting MongoDB connection variables + cd WEB-INF/classes/ + sed -i 's/spring.data.mongodb.host=localhost/spring.data.mongodb.host='"$MONGO_MONGODB_SERVICE_HOST"'/g' application.properties + sed -i 's/# Mongo/# Mongo\nspring.data.mongodb.username=root\nspring.data.mongodb.password='"$MONGODB_ROOT_PASSWORD"'\nspring.data.mongodb.authentication-database=admin/g' application.properties + + cd /var/lib/tomcat/webapps/system-modeller/WEB-INF/classes/ + sed -i 's/reset.on.start=true/reset.on.start=false/g' application.properties + sed -i 's/reset.on.start=true/reset.on.start=false/g' application-production.properties + +else + echo "Restart not due to upgrade: something must have crashed :(" +fi + +echo "Starting tomcat7" + +cd /var/lib/tomcat/bin +./catalina.sh run + + +#MongoDB GCloud Settings +#spring.data.mongodb.username=root +#spring.data.mongodb.password=0Z5XQR5IEJ +#spring.data.mongodb.authentication-database=admin +#spring.data.mongodb.host=10.3.246.90 +#spring.data.mongodb.port=27017 +#spring.data.mongodb.database=system-modeller \ No newline at end of file diff --git a/vagrant/base.sh b/vagrant/base.sh index 547159f..49786c9 100644 --- a/vagrant/base.sh +++ b/vagrant/base.sh @@ -6,20 +6,31 @@ export CI_COMMIT_SHORT_SHA="12345qwerty" # this would be set by GitLab export GCP_HOST="eu.gcr.io" # these are pointing to the GCP K8s instance export GCP_PROJECT_ID="test" -### clone system-modeller repo (putting this first as it is likely to fail with SSH issues) -# add host keys to the end of the known_hosts file (keys generated using `ssh-keyscan iglab.it-innovation.soton.ac.uk`) +export BASE_IMAGE=$GCP_HOST/$GCP_PROJECT_ID/ssm-base:alpine +export BUILD_IMAGE=build-img:$CI_COMMIT_SHORT_SHA +export BUILD_CONTAINER=build-cont-$CI_COMMIT_SHORT_SHA +export TEST_IMAGE=test-img:$CI_COMMIT_SHORT_SHA +export DEPLOYMENT_IMAGE=$GCP_HOST/$GCP_PROJECT_ID/ssm-deployment:$CI_COMMIT_SHORT_SHA + +### Clone system-modeller repo (putting this first as it is likely to fail with SSH issues) + +# This would not be needed when all these mechanisms are included in the repo. +# Add host keys to the end of the known_hosts file (keys generated using `ssh-keyscan iglab.it-innovation.soton.ac.uk`) cat << KEYS >> ~/.ssh/known_hosts iglab.it-innovation.soton.ac.uk ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAUhlAKXym/8PWBqq76jUAldx7GADjUAuJo2czqtxN4fAvJRxF/Bfw2JEUHOX22t7ABY7m/8YyHL/7YJVSdXTK78DLsAX8EbXm0kVIXkG+dm38GGqvPx2mIJU3o1tLe6R9w4pZX9ft3oqCtfmJco7mPj/5hAcQulPWr8yUZ5c+OwwWXYp7ukoPVBPVjBa1TiDae7Bz/TE+iuvCe6n4Vot1uzauZo9rBTPeIeW2kH/TVJRorfPaM/Ci+AHnJTPnrwJdR+FKgxUb56goJVkhBo2mH4gYY5We+rxOPMEpUTczM6wJbDnMPidaJimb613lghlHtveil9yiXjy7KShZ1QhL iglab.it-innovation.soton.ac.uk ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBF5S+PBRXgdN/6HD90uKVdJK8zv4uNRB2vEPXUhHHkcpF8OiR8CRDrL++eTQsPP/VH1UF4fIcODQnD+AVuMXlE= iglab.it-innovation.soton.ac.uk ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPOm5Jmu8yQhyBFrHbIAqOl4rk+KV3NSb4HCYlRoa0MB KEYS + # access vagrant user's SSH_AUTH_SOCK as root in order to use the SSH agent on the host # also need 'config.ssh.forward_agent' = true in Vagrantfile SOCKET=$(ls -1 --sort t /tmp/ssh-*/agent.* | head -1) export SSH_AUTH_SOCK="${SOCKET}" + # clone (requires your private key to be available inside the Vagrant VM, can be done with a key agent) git clone git@iglab.it-innovation.soton.ac.uk:Security/system-modeller.git +### Update VM apt-get update apt-get -y upgrade @@ -54,38 +65,39 @@ usermod -aG docker vagrant ### Build base docker image # the name of the image (arg "-t") includes context to do with GCP -docker build -t "$GCP_HOST/$GCP_PROJECT_ID/ssm-base:alpine" -f /vagrant/docker/Dockerfile_base . +docker build -t $BASE_IMAGE -f /vagrant/docker/Dockerfile_base . # log in to docker registry #cat keyfile.json | docker login -u _json_key --password-stdin "https://$GCP_HOST" # push image to registry -#docker push "$GCP_HOST/$GCP_PROJECT_ID/ssm-base:alpine" +#docker push $BASE_IMAGE ### Build SSM inside base image # The "system-modeller" arg sets the "context" to that folder so that it picks up the right files; # The name of the image includes the SHA of the git commit plus some context to do with GCP +# TODO: pass in the image name ising $BASE_IMAGE instead of the individual variable parts # # Log in to registry so that build step below can retrieve ssm-base from there # cat keyfile.json | docker login -u _json_key --password-stdin "https://$GCP_HOST" -docker build -t "build-img:$CI_COMMIT_SHORT_SHA" \ - --build-arg GCP_HOST="$GCP_HOST" \ - --build-arg GCP_PROJECT_ID="$GCP_PROJECT_ID" \ +docker build -t $BUILD_IMAGE \ + --build-arg GCP_HOST=$GCP_HOST \ + --build-arg GCP_PROJECT_ID=$GCP_PROJECT_ID \ -f /vagrant/docker/Dockerfile_build system-modeller ### Extract the build artifacts # Create an instance of the build-img (same as docker run, but the container is not started) -docker create --name "build-cont-$CI_COMMIT_SHORT_SHA" "build-img:$CI_COMMIT_SHORT_SHA" +docker create --name $BUILD_CONTAINER $BUILD_IMAGE # Copy out the build folder -docker cp "build-cont-$CI_COMMIT_SHORT_SHA:/build" . +docker cp $BUILD_CONTAINER:/build . # Delete the instance and the image (after testing they exist) -test ! -z "$(docker ps -a | grep build-cont-$CI_COMMIT_SHORT_SHA)" && docker rm "build-cont-$CI_COMMIT_SHORT_SHA" -#test ! -z "$(docker images -q test-img:$CI_COMMIT_SHORT_SHA)" && docker rmi "build-img:$CI_COMMIT_SHORT_SHA" +test ! -z "$(docker ps -a | grep $BUILD_CONTAINER)" && docker rm $BUILD_CONTAINER +#test ! -z "$(docker images -q test-img:$CI_COMMIT_SHORT_SHA)" && docker rmi $BUILD_IMAGE -### run tests +### Run tests # Create a network docker network create "test-network-$CI_COMMIT_SHORT_SHA" --driver bridge @@ -97,30 +109,74 @@ docker network create "test-network-$CI_COMMIT_SHORT_SHA" --driver bridge export MONGO_MONGODB_SERVICE_HOST="mongo-server-$CI_COMMIT_SHORT_SHA" export MONGODB_ROOT_PASSWORD="root" docker run -d --name "$MONGO_MONGODB_SERVICE_HOST" \ - -e MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD \ + --env MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD \ --network "test-network-$CI_COMMIT_SHORT_SHA" bitnami/mongodb:latest # # Log in to registry so that build step below can retrieve ssm-base from there # cat keyfile.json | docker login -u _json_key --password-stdin "https://$GCP_HOST" -# Make a test-img (based on build-img, see Dockerfile_test), connect it to the network -docker build -t "test-img:$CI_COMMIT_SHORT_SHA" \ - --network "test-network-$CI_COMMIT_SHORT_SHA" \ - --build-arg GCP_HOST="$GCP_HOST" \ - --build-arg GCP_PROJECT_ID="$GCP_PROJECT_ID" \ - --build-arg CI_COMMIT_SHORT_SHA="$CI_COMMIT_SHORT_SHA" \ - --build-arg MONGO_MONGODB_SERVICE_HOST="$MONGO_MONGODB_SERVICE_HOST" \ +# Make a test-img (based on build-img, see Dockerfile_test), connect it to the network. +# NB: the " || true" on the end of the command is there to make the line return no error: the tests are failing so if we did not have this then the script would exit here (because of the options set on line 1) +docker build -t $TEST_IMAGE \ + --network test-network-$CI_COMMIT_SHORT_SHA \ + --build-arg GCP_HOST=$GCP_HOST \ + --build-arg GCP_PROJECT_ID=$GCP_PROJECT_ID \ + --build-arg CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA \ + --build-arg MONGO_MONGODB_SERVICE_HOST=$MONGO_MONGODB_SERVICE_HOST \ --build-arg MONGODB_ROOT_PASSWORD="$MONGODB_ROOT_PASSWORD" \ - -f /vagrant/docker/Dockerfile_test . + -f /vagrant/docker/Dockerfile_test . || true # Delete the test-img, mongo instance and network -# test ! -z "$(docker images -q test-img:$CI_COMMIT_SHORT_SHA)" && docker rmi "test-img:$CI_COMMIT_SHORT_SHA" +test ! -z "$(docker images -q $TEST_IMAGE)" && docker rmi $TEST_IMAGE docker top "mongo-server-$CI_COMMIT_SHORT_SHA" && docker stop "mongo-server-$CI_COMMIT_SHORT_SHA" && docker rm "mongo-server-$CI_COMMIT_SHORT_SHA" docker network rm "test-network-$CI_COMMIT_SHORT_SHA" -## Docker commands +### Build deployment image + +# Copy in docker folder from host to VM to make deploy script available to container (will not be needed when this is integrated into the SSM repo) +cp -a /vagrant/docker/ . + +# Dockerfile_deployment starts with ssm-base and copies in the built WAR file and the deploy script. + +# # Log in to registry so that the push step below can upload the image +# cat keyfile.json | docker login -u _json_key --password-stdin "https://$GCP_HOST" +# Not sure why, but Niall's build also had --build-arg CI_JOB_ID="$CI_JOB_ID" \ +docker build -t $DEPLOYMENT_IMAGE \ + --build-arg GCP_HOST=$GCP_HOST \ + --build-arg GCP_PROJECT_ID=$GCP_PROJECT_ID \ + -f /vagrant/docker/Dockerfile_deployment . +#docker push "$DEPLOYMENT_IMAGE" +#echo "Pushed new image to private container registry under the tag: $CI_COMMIT_SHORT_SHA. If you have thoroughly tested this version, run update-deployment to push these changes to GCP." +# after_script: +# - docker system prune -f # this removes any dead containers etc to minimise storage needed + +### Deploy SSM with MongoDB + +docker network create "deploy-network-$CI_COMMIT_SHORT_SHA" --driver bridge + +export MONGO_MONGODB_SERVICE_HOST="mongo-server-$CI_COMMIT_SHORT_SHA" +export MONGODB_ROOT_PASSWORD="root" +docker run -d --name "$MONGO_MONGODB_SERVICE_HOST" \ + --env MONGODB_ROOT_PASSWORD=$MONGODB_ROOT_PASSWORD \ + --network "deploy-network-$CI_COMMIT_SHORT_SHA" \ + bitnami/mongodb:latest + +# Expose port 8080 of the ssm container as 8080 in the host +# If running this through vagrant then a port forward is needed there as well +docker run -d --name "ssm-$CI_COMMIT_SHORT_SHA" \ + --env MONGO_MONGODB_SERVICE_HOST="$MONGO_MONGODB_SERVICE_HOST" \ + --env MONGODB_ROOT_PASSWORD="$MONGODB_ROOT_PASSWORD" \ + --network "deploy-network-$CI_COMMIT_SHORT_SHA" \ + --publish 8080:8080 \ + $DEPLOYMENT_IMAGE + + +### Docker stuff + # "docker container ls" only shows running containers ffs # "docker container ls -a" shows all -# "docker rm <containerID>" to delete them +# "docker rm <containerID>" to delete them (may need to do "docker stop <containerID>" first) # "docker run --name <container name> -it <image name>" to create and run container and log in (obviously). "i" for interactive, "t" for attaching a pseudo TTY -# "docker build --no-cache ..." is useful when debugging \ No newline at end of file +# "docker build --no-cache ..." is useful when debugging +# "docker exec -ti <CONTAINER_ID> bash" to attach to a running container with bash shell so you can look around +# In a Dockerfile, any ARG declared before a FROM is undefined after FROM \ No newline at end of file -- GitLab