diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9eb53ea82bae755ad23a03385aaf44e1a98ebf1e..54c80cca042fc224c4cb450888ad45a4c9ea4547 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: lycantropos/cmake
+image: lightspot21/acubesat-ci:latest
 
 variables:
   PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
@@ -14,14 +14,6 @@ stages:
   - test
   - deploy
 
-before_script:
-  - apt-get update -qq && apt-get -qq -y install python3-pip && python3 -m pip install --upgrade pip
-  - python3 -V
-  - python3 -m pip --version
-  - g++ --version
-  - cat /etc/*-release
-  - python3 -m pip install gcovr
-
 build:
   stage: build
   variables:
@@ -54,8 +46,6 @@ tests:
 cppcheck:
   stage: build
   before_script:
-    - echo deb http://deb.debian.org/debian testing main > /etc/apt/sources.list
-    - apt-get update -qq && apt-get -t testing install -y cppcheck
     - cppcheck --version
   script:
     - ci/cppcheck.sh
@@ -63,9 +53,6 @@ cppcheck:
 cppcheck-misra:
   stage: build
   before_script:
-  # install cppcheck from the testing repos in order to get the latest version
-    - echo deb http://deb.debian.org/debian testing main > /etc/apt/sources.list
-    - apt-get update -qq && apt-get -t testing install -y cppcheck && apt-get -t testing install -y python3
     - cppcheck --version
   script:
     - ci/cppcheck-misra.sh
@@ -73,7 +60,6 @@ cppcheck-misra:
 vera:
   stage: build
   before_script:
-    - apt-get update -qq && apt-get install -y -qq vera++
     - vera++ --version
     - cp ci/vera.profile /usr/lib/vera++/profiles/custom
   script:
@@ -84,14 +70,8 @@ clang-tidy:
   variables:
     GIT_SUBMODULE_STRATEGY: normal
     TERM: xterm-color
-  before_script:
-    # Installing the `sid` repository to get the latest version of clang
-    - echo deb http://deb.debian.org/debian sid main > /etc/apt/sources.list
-    - apt-get update -qq && apt-get -t sid install -y -qq clang-tidy-7
-    - clang-tidy-7 --version
   script:
-    # Running with `script` to give clang a tty so that it outputs colours
-    - script -c "bash -x ci/clang-tidy.sh"
+     - ./ci/clang-tidy.sh
 
 pages:
   stage: deploy
@@ -103,8 +83,6 @@ pages:
   variables:
     GIT_SUBMODULE_STRATEGY: normal
   script:
-    - apt-get install -qq -y doxygen graphviz lcov
-  after_script:
     - ./ci/pages_deploy.sh
     - echo -e "\e[1;36mPublic directory contents\e[0m" && ls -l public/coverage  # Print directory contents for debugging
   artifacts:
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..5d89f392d3d1e9e841f887a9f80e9c4d6350792f
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,38 @@
+# This is the Dockerfile for the lightspot21/acubesat-ci:latest
+# Docker image used at the pipeline. Please take care to generate 
+# and push a new image to the lightspot21/acubesat-ci repo every 
+# 1-2 weeks in order to ensure that the tools are at the latest version.
+# 
+# P.S. Tag properly your images with --tag lightspot21/acubesat-ci when
+# building.
+
+FROM alpine:latest
+
+# Set a new work directory. DO NOT DELETE THE LINE BELOW
+WORKDIR /root/
+
+# Set up clang-tidy version 8
+RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" \
+    >> /etc/apk/repositories && apk update && \
+    apk add --no-cache --virtual git-deps git && \
+    apk add --no-cache build-base cmake && \
+    apk add --no-cache python3 && \
+    git clone --depth=1 https://github.com/llvm/llvm-project.git -b release/8.x && \
+    cmake \
+    -DLLVM_ENABLE_PROJECTS="clang-tools-extra;clang" \
+    -DCMAKE_BUILD_TYPE=MinSizeRel \
+    -DLLVM_TARGETS_TO_BUILD="host" \
+    -G "Unix Makefiles" ./llvm-project/llvm && \
+    make -j$(nproc) clang-tidy && mv bin/clang-tidy /usr/bin/clang-tidy && \
+    rm -rf * && apk del git-deps
+
+# Update package lists and install cmake, cppcheck, doxygen, vera++, 
+# gcc and lcov with their dependencies
+RUN apk add --no-cache findutils python3-dev \
+    cppcheck doxygen vera++@testing lcov@testing
+
+# Install gcovr
+RUN python3 -m pip install gcovr
+
+# Start a new shell
+ENTRYPOINT ["/bin/sh", "-c"]
diff --git a/ci/.clang-tidy b/ci/.clang-tidy
index 38beddf8e90c12aa96ede94f6d80bf27cc253aef..478e052795977bbfe87cab6a8dc73eeeee60e665 100644
--- a/ci/.clang-tidy
+++ b/ci/.clang-tidy
@@ -4,7 +4,7 @@ Checks:          >
   clang-analyzer-*,
   bugprone-*,
   cert-*,
-  cppcoreguidelines-*,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-bounds-constant-array-index,
+  cppcoreguidelines-*,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-avoid-c-arrays,
   misc-*,-misc-non-private-member-variables-in-classes,
   fuchsia-multiple-inheritance,
   google-*,-google-readability-todo,
@@ -17,7 +17,7 @@ Checks:          >
   misc-*,
   -misc-non-private-member-variables-in-classes,
   performance-*,
-  readability-*,
+  readability-*,-readability-magic-numbers,
   zircon-*
 WarningsAsErrors: '*,-misc-unused-parameters,-llvm-header-guard,-cppcoreguidelines-pro-type-member-init,-google-runtime-references,-clang-diagnostic-tautological-constant-out-of-range-compare,-readability-redundant-declaration,-modernize-use-equals-default,-fuchsia-statically-constructed-objects,-hicpp-signed-bitwise,-cert-err58-cpp,-clang-diagnostic-error,-misc-noexcept-move-constructor'
 HeaderFilterRegex: 'ecss-services\/((?!lib\/).)*$'
diff --git a/ci/clang-tidy.sh b/ci/clang-tidy.sh
index bdff8166981a4312ab0a2c28423a5359af80ad59..bf45a2eb46252b15df6fd7474720622429c86cc1 100755
--- a/ci/clang-tidy.sh
+++ b/ci/clang-tidy.sh
@@ -10,6 +10,10 @@
 echo -e "\033[0;34mRunning clang-tidy...\033[0m"
 
 cd "$(dirname "$0")"
-clang-tidy-7 `find ../src/ -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` \
-    -extra-arg=-fcolor-diagnostics  -- -std=c++17 -I../inc \
-    -I/usr/include/c++/7/ -I/usr/include/x86_64-linux-gnu/c++/7 -I../lib/etl/include
+GCCVERSION=`g++ -dumpversion`
+
+clang-tidy `find ../src/ -type f -regextype posix-egrep -regex '.*\.(cpp|hpp|c|h)'` \
+    -extra-arg=-fcolor-diagnostics -- -std=c++17 -I../inc -I../lib/etl/include \
+    -I/usr/include/c++/$GCCVERSION -I/usr/include/x86_64-linux-gnu/c++/$GCCVERSION \
+    -I/usr/include/c++/$GCCVERSION/$MACHTYPE
+
diff --git a/inc/ECSS_Definitions.hpp b/inc/ECSS_Definitions.hpp
index 2fe9218df54d72b0c965e75983ec99bb312d0f7d..2eecf34c200ed0dc09649dc0eba09ba21cb118fa 100644
--- a/inc/ECSS_Definitions.hpp
+++ b/inc/ECSS_Definitions.hpp
@@ -1,11 +1,11 @@
 #ifndef ECSS_SERVICES_ECSS_DEFINITIONS_H
 #define ECSS_SERVICES_ECSS_DEFINITIONS_H
 
-#define ECSS_MAX_MESSAGE_SIZE 1024u
+#define ECSS_MAX_MESSAGE_SIZE 1024U
 
-#define ECSS_MAX_STRING_SIZE 256u
+#define ECSS_MAX_STRING_SIZE 256U
 
-#define ECSS_MAX_FIXED_OCTET_STRING_SIZE 256u // For the ST13 large packet transfer service
+#define ECSS_MAX_FIXED_OCTET_STRING_SIZE 256U // For the ST13 large packet transfer service
 
 // 7.4.1
 #define CCSDS_PACKET_VERSION 0
diff --git a/inc/Helpers/TimeHelper.hpp b/inc/Helpers/TimeHelper.hpp
index 7cd1920d5343fa6b8186f3c377369462a1cc8a91..526b80333fbc584e87edbd3115ca3cf413766030 100644
--- a/inc/Helpers/TimeHelper.hpp
+++ b/inc/Helpers/TimeHelper.hpp
@@ -5,9 +5,9 @@
 #include <Message.hpp>
 #include "TimeAndDate.hpp"
 
-#define SECONDS_PER_MINUTE 60u
-#define SECONDS_PER_HOUR 3600u
-#define SECONDS_PER_DAY 86400u
+#define SECONDS_PER_MINUTE 60U
+#define SECONDS_PER_HOUR 3600U
+#define SECONDS_PER_DAY 86400U
 
 /**
  * @todo If we use CUC time format then we should keep leap seconds up to date. Leap seconds are added in undefined
diff --git a/src/Helpers/CRCHelper.cpp b/src/Helpers/CRCHelper.cpp
index dda87aa34d4a7be7c539ab5642ee48cc81fc6f71..1e6a28fd4c3808bcf5459a6378cd21e4f7d7ef52 100644
--- a/src/Helpers/CRCHelper.cpp
+++ b/src/Helpers/CRCHelper.cpp
@@ -4,23 +4,23 @@
 
 uint16_t CRCHelper::calculateCRC(const uint8_t* message, uint32_t length) {
 	// shift register contains all 1's initially (ECSS-E-ST-70-41C, Annex B - CRC and ISO checksum)
-	uint16_t shiftReg = 0xFFFFu;
+	uint16_t shiftReg = 0xFFFFU;
 
 	// CRC16-CCITT generator polynomial (as specified in standard)
-	uint16_t polynomial = 0x1021u;
+	uint16_t polynomial = 0x1021U;
 
 	for (uint32_t i = 0; i < length; i++) {
 		// "copy" (XOR w/ existing contents) the current msg bits into the MSB of the shift register
-		shiftReg ^= (message[i] << 8u);
+		shiftReg ^= (message[i] << 8U);
 
 		for (int j = 0; j < 8; j++) {
 			// if the MSB is set, the bitwise AND gives 1
-			if ((shiftReg & 0x8000u) != 0u) {
+			if ((shiftReg & 0x8000U) != 0U) {
 				// toss out of the register the MSB and divide (XOR) its content with the generator
-				shiftReg = ((shiftReg << 1u) ^ polynomial);
+				shiftReg = ((shiftReg << 1U) ^ polynomial);
 			} else {
 				// just toss out the MSB and make room for a new bit
-				shiftReg <<= 1u;
+				shiftReg <<= 1U;
 			}
 		}
 	}
diff --git a/src/Helpers/TimeHelper.cpp b/src/Helpers/TimeHelper.cpp
index 16b6e16229b6469d6e0c554385be6e0f0ec665e7..04792af7c90b0be0153d8212aa3af4262673870b 100644
--- a/src/Helpers/TimeHelper.cpp
+++ b/src/Helpers/TimeHelper.cpp
@@ -25,8 +25,8 @@ uint32_t TimeHelper::utcToSeconds(TimeAndDate& TimeInfo) {
 		secs += (IsLeapYear(y) ? 366 : 365) * SECONDS_PER_DAY;
 	}
 	for (uint16_t m = 1; m < TimeInfo.month; ++m) {
-		secs += DaysOfMonth[m - 1u] * SECONDS_PER_DAY;
-		if ((m == 2u) && IsLeapYear(TimeInfo.year)) {
+		secs += DaysOfMonth[m - 1U] * SECONDS_PER_DAY;
+		if ((m == 2U) && IsLeapYear(TimeInfo.year)) {
 			secs += SECONDS_PER_DAY;
 		}
 	}
@@ -62,7 +62,7 @@ struct TimeAndDate TimeHelper::secondsToUTC(uint32_t seconds) {
 		TimeInfo.month++;
 		seconds -= (DaysOfMonth[i] * SECONDS_PER_DAY);
 		i++;
-		if ((i == 1u) && IsLeapYear(TimeInfo.year)) {
+		if ((i == 1U) && IsLeapYear(TimeInfo.year)) {
 			if (seconds <= (28 * SECONDS_PER_DAY)) {
 				break;
 			}
@@ -121,7 +121,7 @@ TimeAndDate TimeHelper::parseCDStimeFormat(const uint8_t* data) {
 	uint32_t msOfDay = ((static_cast<uint32_t>(data[2])) << 24) | ((static_cast<uint32_t>(data[3]))) << 16 |
 	                   ((static_cast<uint32_t>(data[4]))) << 8 | (static_cast<uint32_t>(data[5]));
 
-	uint32_t seconds = (elapsedDays * SECONDS_PER_DAY) + (msOfDay / 1000u);
+	uint32_t seconds = (elapsedDays * SECONDS_PER_DAY) + (msOfDay / 1000U);
 
 	return secondsToUTC(seconds);
 }
diff --git a/src/Message.cpp b/src/Message.cpp
index efedb65c16b2388fc6a87326cb0ffbcd35f2fac9..7ff70f30a13882c56b626f4c0b071b8275549c0c 100644
--- a/src/Message.cpp
+++ b/src/Message.cpp
@@ -84,7 +84,7 @@ uint16_t Message::readBits(uint8_t numBits) {
 		if ((currentBit + numBits) >= 8) {
 			auto bitsToAddNow = static_cast<uint8_t>(8 - currentBit);
 
-			uint8_t mask = ((1u << bitsToAddNow) - 1u);
+			uint8_t mask = ((1U << bitsToAddNow) - 1U);
 			uint8_t maskedData = data[readPosition] & mask;
 			value |= maskedData << (numBits - bitsToAddNow);
 
diff --git a/src/MessageParser.cpp b/src/MessageParser.cpp
index 29300cdbf7c0b761f443c7ee189f6f59bfb4589b..656e0756734d5ec788aae0a043e138a2f231451c 100644
--- a/src/MessageParser.cpp
+++ b/src/MessageParser.cpp
@@ -52,10 +52,10 @@ Message MessageParser::parse(uint8_t* data, uint32_t length) {
 	auto sequenceFlags = static_cast<uint8_t>(packetSequenceControl >> 14);
 
 	// Returning an internal error, since the Message is not available yet
-	ASSERT_INTERNAL(versionNumber == 0u, ErrorHandler::UnacceptablePacket);
-	ASSERT_INTERNAL(secondaryHeaderFlag == 1u, ErrorHandler::UnacceptablePacket);
-	ASSERT_INTERNAL(sequenceFlags == 0x3u, ErrorHandler::UnacceptablePacket);
-	ASSERT_INTERNAL(packetDataLength == (length - 6u), ErrorHandler::UnacceptablePacket);
+	ASSERT_INTERNAL(versionNumber == 0U, ErrorHandler::UnacceptablePacket);
+	ASSERT_INTERNAL(secondaryHeaderFlag == 1U, ErrorHandler::UnacceptablePacket);
+	ASSERT_INTERNAL(sequenceFlags == 0x3U, ErrorHandler::UnacceptablePacket);
+	ASSERT_INTERNAL(packetDataLength == (length - 6U), ErrorHandler::UnacceptablePacket);
 
 	Message message(0, 0, packetType, APID);
 
@@ -78,7 +78,7 @@ void MessageParser::parseTC(const uint8_t* data, uint16_t length, Message& messa
 
 	// todo: Fix this parsing function, because it assumes PUS header in data, which is not true
 	//  with the current implementation
-	ErrorHandler::assertRequest(pusVersion == 2u, message, ErrorHandler::UnacceptableMessage);
+	ErrorHandler::assertRequest(pusVersion == 2U, message, ErrorHandler::UnacceptableMessage);
 
 	// Remove the length of the header
 	length -= 5;
@@ -126,7 +126,7 @@ void MessageParser::parseTM(const uint8_t* data, uint16_t length, Message& messa
 	uint8_t serviceType = data[1];
 	uint8_t messageType = data[2];
 
-	ErrorHandler::assertRequest(pusVersion == 2u, message, ErrorHandler::UnacceptableMessage);
+	ErrorHandler::assertRequest(pusVersion == 2U, message, ErrorHandler::UnacceptableMessage);
 
 	// Remove the length of the header
 	length -= 5;
diff --git a/src/Services/EventActionService.cpp b/src/Services/EventActionService.cpp
index e3788002c83a8c7b175e8c150a91880919c8f4f7..9ed4f9b6213752afc9b74efc49cf30fff61b1819 100644
--- a/src/Services/EventActionService.cpp
+++ b/src/Services/EventActionService.cpp
@@ -77,7 +77,7 @@ void EventActionService::enableEventActionDefinitions(Message& message) {
 	// TC[19,4]
 	message.assertTC(19, 4);
 	uint16_t numberOfEventActionDefinitions = message.readUint16();
-	if (numberOfEventActionDefinitions != 0u) {
+	if (numberOfEventActionDefinitions != 0U) {
 		for (uint16_t i = 0; i < numberOfEventActionDefinitions; i++) {
 			message.skipBytes(2); // Skips reading the application ID
 			uint16_t eventDefinitionID = message.readEnum16();
@@ -110,7 +110,7 @@ void EventActionService::disableEventActionDefinitions(Message& message) {
 	// TC[19,5]
 	message.assertTC(19, 5);
 	uint16_t numberOfEventActionDefinitions = message.readUint16();
-	if (numberOfEventActionDefinitions != 0u) {
+	if (numberOfEventActionDefinitions != 0U) {
 		for (uint16_t i = 0; i < numberOfEventActionDefinitions; i++) {
 			message.skipBytes(2); // Skips reading applicationID
 			uint16_t eventDefinitionID = message.readEnum16();
diff --git a/src/Services/EventReportService.cpp b/src/Services/EventReportService.cpp
index cbf8ee72ae08d669e65537d6cd6d08314ef28c41..baf2ba484347c417a6400cbf73f990baee8798bc 100644
--- a/src/Services/EventReportService.cpp
+++ b/src/Services/EventReportService.cpp
@@ -120,7 +120,7 @@ void EventReportService::listOfDisabledEventsReport() {
 
 	uint16_t numberOfDisabledEvents = stateOfEvents.size() - stateOfEvents.count();
 	report.appendHalfword(numberOfDisabledEvents);
-	for (uint16_t i = 0; i < stateOfEvents.size(); i++) {
+	for (size_t i = 0; i < stateOfEvents.size(); i++) {
 		if (not stateOfEvents[i]) {
 			report.appendEnum16(i);
 		}
diff --git a/src/Services/LargePacketTransferService.cpp b/src/Services/LargePacketTransferService.cpp
index 15b0e3c3609c41f242a6f6830f570b5598a30f9a..95b3cafafd1e89b51999563dd8473bd2c989275c 100644
--- a/src/Services/LargePacketTransferService.cpp
+++ b/src/Services/LargePacketTransferService.cpp
@@ -69,7 +69,7 @@ void LargePacketTransferService::split(Message& message, uint16_t largeMessageTr
 	stringPart = dataPart;
 	firstDownlinkPartReport(largeMessageTransactionIdentifier, 0, stringPart);
 
-	for (uint16_t part = 1; part < (parts - 1u); part++){
+	for (uint16_t part = 1; part < (parts - 1U); part++){
 		for (uint16_t i = 0; i < ECSS_MAX_FIXED_OCTET_STRING_SIZE; i++){
 			dataPart[i] = message.data[positionCounter];
 			positionCounter++;
@@ -86,5 +86,5 @@ void LargePacketTransferService::split(Message& message, uint16_t largeMessageTr
 		positionCounter++;
 	}
 	stringPart = dataPart;
-	lastDownlinkPartReport(largeMessageTransactionIdentifier, (parts - 1u), stringPart);
+	lastDownlinkPartReport(largeMessageTransactionIdentifier, (parts - 1U), stringPart);
 }
diff --git a/src/Services/ParameterService.cpp b/src/Services/ParameterService.cpp
index 44d766820f6eac6e67de2e502a52db608c7b5eac..018de09f2a197bc8f87a66b518d5618e5b16ee26 100644
--- a/src/Services/ParameterService.cpp
+++ b/src/Services/ParameterService.cpp
@@ -12,12 +12,12 @@ ParameterService::ParameterService() {
 	time_t currTime = time(nullptr);
 	struct tm* today = localtime(&currTime);
 
-	Parameter test1, test2;
-
+	Parameter test1;
 	test1.settingData = today->tm_hour; // the current hour
 	test1.ptc = 3; // unsigned int
 	test1.pfc = 14; // 32 bits
 
+	Parameter test2;
 	test2.settingData = today->tm_min; // the current minute
 	test2.ptc = 3; // unsigned int
 	test2.pfc = 14; // 32 bits
diff --git a/src/main.cpp b/src/main.cpp
index aed43a835568e32cffa5c32ba04f5dcbcb8ce5a6..d317286d26f07da765aaf539f67bda78371783c3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -304,7 +304,8 @@ int main() {
 	std::cout << "\nCurrent time in seconds (UNIX epoch): " << currentTime << std::endl;
 
 	Message receivedMsg = Message(11, 1, Message::TC, 1);
-	Message testMessage1(6, 5, Message::TC, 1), testMessage2(4, 5, Message::TC, 1);
+	Message testMessage1(6, 5, Message::TC, 1);
+	Message testMessage2(4, 5, Message::TC, 1);
 	testMessage1.appendUint16(4253); // Append dummy data
 	testMessage2.appendUint16(45667); // Append dummy data
 
@@ -314,10 +315,10 @@ int main() {
 	receivedMsg = Message(11, 4, Message::TC, 1);
 	receivedMsg.appendUint16(2); // Total number of requests
 
-	receivedMsg.appendUint32(currentTime + 1556435u);
+	receivedMsg.appendUint32(currentTime + 1556435U);
 	receivedMsg.appendString(msgParser.convertTCToStr(testMessage1));
 
-	receivedMsg.appendUint32(currentTime + 1957232u);
+	receivedMsg.appendUint32(currentTime + 1957232U);
 	receivedMsg.appendString(msgParser.convertTCToStr(testMessage2));
 	timeBasedSchedulingService.insertActivities(receivedMsg);