diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de73135 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea +.env +.DS_Store +._* +*.code-workspace +.vscode diff --git a/.jenkins/Jenkinsfile b/.jenkins/Jenkinsfile new file mode 100644 index 0000000..aac0239 --- /dev/null +++ b/.jenkins/Jenkinsfile @@ -0,0 +1,125 @@ +pipeline { + agent { + label 'docker-multiarch' + } + options { + buildDiscarder(logRotator(numToKeepStr: '5')) + disableConcurrentBuilds() + ansiColor('xterm') + } + environment { + IMAGE = 'nginx-full' + BUILDX_NAME = "${IMAGE}_${GIT_BRANCH}" + BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('/', '-')}" + // Software versions; OpenResty does not support Lua >= 5.2 + OPENRESTY_VERSION = '1.19.3.1' + LUA_VERSION = '5.1.5' + LUAROCKS_VERSION = '3.3.1' + } + stages { + stage('Environment') { + parallel { + stage('Master') { + when { + branch 'master' + } + steps { + script { + env.BASE_TAG = 'latest' + env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:${BASE_TAG}" + env.BUILDX_PUSH_TAGS_NODE = "-t docker.io/jc21/${IMAGE}:node" + env.BUILDX_PUSH_TAGS_GOLANG = "-t docker.io/jc21/${IMAGE}:golang" + } + } + } + stage('Other') { + when { + not { + branch 'master' + } + } + steps { + script { + // Defaults to the Branch name, which is applies to all branches AND pr's + env.BASE_TAG = "github-${BRANCH_LOWER}" + env.BUILDX_PUSH_TAGS = "-t docker.io/jc21/${IMAGE}:${BASE_TAG}" + env.BUILDX_PUSH_TAGS_NODE = "${BUILDX_PUSH_TAGS}-node" + env.BUILDX_PUSH_TAGS_GOLANG = "${BUILDX_PUSH_TAGS}-golang" + } + } + } + } + } + stage('Base Build') { + environment { + BUILDX_NAME = "${IMAGE}_${GIT_BRANCH}_base" + } + steps { + withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'DOCKER_PASS', usernameVariable: 'DOCKER_USER')]) { + sh 'docker login -u "${DOCKER_USER}" -p "${DOCKER_PASS}"' + sh "./scripts/buildx --push -f docker/Dockerfile ${BUILDX_PUSH_TAGS}" + } + } + } + stage('Other Builds') { + parallel { + stage('Golang') { + environment { + BUILDX_NAME = "${IMAGE}_${GIT_BRANCH}_golang" + } + steps { + withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'DOCKER_PASS', usernameVariable: 'DOCKER_USER')]) { + sh 'docker login -u "${DOCKER_USER}" -p "${DOCKER_PASS}"' + sh "./scripts/buildx --push -f docker/Dockerfile.golang ${BUILDX_PUSH_TAGS_GOLANG}" + } + } + } + stage('Node') { + environment { + BUILDX_NAME = "${IMAGE}_${GIT_BRANCH}_node" + } + steps { + withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'DOCKER_PASS', usernameVariable: 'DOCKER_USER')]) { + sh 'docker login -u "${DOCKER_USER}" -p "${DOCKER_PASS}"' + sh "./scripts/buildx --push -f docker/Dockerfile.node ${BUILDX_PUSH_TAGS_NODE}" + } + } + } + } + } + stage('PR Comment') { + when { + allOf { + changeRequest() + not { + equals expected: 'UNSTABLE', actual: currentBuild.result + } + } + } + steps { + script { + def comment = pullRequest.comment("""Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/jc21/${IMAGE}) as: + +- `jc21/${IMAGE}:github-${BRANCH_LOWER}` +- `jc21/${IMAGE}:github-${BRANCH_LOWER}-node` +- `jc21/${IMAGE}:github-${BRANCH_LOWER}-golang` +""") + } + } + } + } + post { + success { + juxtapose event: 'success' + sh 'figlet "SUCCESS"' + } + failure { + juxtapose event: 'failure' + sh 'figlet "FAILURE"' + } + unstable { + juxtapose event: 'unstable' + sh 'figlet "UNSTABLE"' + } + } +} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..02dc753 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,87 @@ +############# +# Go Builder +############# + +FROM --platform=${TARGETPLATFORM:-linux/amd64} golang as go + +ENV MKCERT_VERSION=1.4.2 +RUN mkdir /workspace +WORKDIR /workspace +RUN go get github.com/amacneil/dbmate +RUN wget -O mkcert.tgz "https://github.com/FiloSottile/mkcert/archive/v${MKCERT_VERSION}.tar.gz" +RUN tar -xzf mkcert.tgz +WORKDIR "/workspace/mkcert-${MKCERT_VERSION}" +RUN go build -ldflags "-X main.Version=v${MKCERT_VERSION}" -o /bin/mkcert + +############# +# Nginx Builder +############# + +FROM --platform=${TARGETPLATFORM:-linux/amd64} debian:stable-slim as builder + +ARG OPENRESTY_VERSION +ARG LUA_VERSION +ARG LUAROCKS_VERSION + +RUN apt-get update \ + && apt-get install -y wget build-essential libreadline-dev openssl unzip libncurses-dev libpcre3-dev libssl-dev zlib1g-dev + +# Lua build +ADD ./scripts/build-lua /tmp/build-lua +RUN /tmp/build-lua + +# Nginx build +ADD ./scripts/build-openresty /tmp/build-openresty +RUN /tmp/build-openresty + +############# +# Final Image +############# + +FROM --platform=${TARGETPLATFORM:-linux/amd64} debian:stable-slim +LABEL maintainer="Jamie Curnow " + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# Env var for bashrc +ARG OPENRESTY_VERSION +ENV OPENRESTY_VERSION=${OPENRESTY_VERSION} + +ARG TARGETPLATFORM +RUN echo "Base: debian:stable-slim, ${TARGETPLATFORM:-linux/amd64}" > /built-for-arch + +# OpenResty uses LuaJIT which has a dependency on GCC +RUN apt-get update \ + && apt-get install -y curl figlet openssl libpcre3 zlib1g apache2-utils tzdata perl libreadline7 unzip libncurses6 make gcc \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +ADD ./files/.bashrc /root/.bashrc + +# Copy lua and luarocks builds from first image +COPY --from=builder /tmp/lua /tmp/lua +COPY --from=builder /tmp/luarocks /tmp/luarocks +ADD ./scripts/install-lua /tmp/install-lua + +# Copy openresty build from first image +COPY --from=builder /tmp/openresty /tmp/openresty +ADD ./scripts/install-openresty /tmp/install-openresty + +# Copy golang built packages +COPY --from=go /bin/mkcert /bin/mkcert +COPY --from=go /go/bin/dbmate /bin/dbmate + +RUN /tmp/install-lua \ + && /tmp/install-openresty \ + && rm -f /tmp/install-lua \ + && rm -f /tmp/install-openresty \ + && apt-get remove -y make gcc \ + && apt-get autoremove -y + +LABEL org.label-schema.schema-version="1.0" \ + org.label-schema.license="MIT" \ + org.label-schema.name="nginx-full" \ + org.label-schema.description="A base image for use by Nginx Proxy Manager" \ + org.label-schema.url="https://github.com/jc21/docker-nginx-full" \ + org.label-schema.vcs-url="https://github.com/jc21/docker-nginx-full.git" \ + org.label-schema.cmd="docker run --rm -ti jc21/nginx-full:latest" diff --git a/docker/Dockerfile.golang b/docker/Dockerfile.golang new file mode 100644 index 0000000..4f67814 --- /dev/null +++ b/docker/Dockerfile.golang @@ -0,0 +1,28 @@ +FROM --platform=${TARGETPLATFORM:-linux/amd64} golang as go +FROM --platform=${TARGETPLATFORM:-linux/amd64} jc21/nginx-full:${BASE_TAG:-latest} + +ARG TARGETPLATFORM + +RUN echo "Golang: jc21/nginx-full:${BASE_TAG:-latest}, ${TARGETPLATFORM:-linux/amd64}" >> /built-for-arch + +LABEL maintainer="Jamie Curnow " + +RUN apt-get update \ + && apt-get install -y wget \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# copy go from golang +COPY --from=go /usr/local/go /usr/local/go + +ENV GOPATH=/opt/go PATH="/usr/local/go/bin:$PATH:/opt/go/bin" +RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" \ + && chmod -R 777 "$GOPATH" \ + && echo "====> ${TARGETPLATFORM}: $(go version)" + +WORKDIR /root + +# Gotools +RUN if [ "$TARGETPLATFORM" == "" ] || [ "$TARGETPLATFORM" == "linux/amd64" ]; then cd /usr && wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.39.0; fi +RUN go get -u github.com/kyoh86/richgo \ + && rm -rf /root/.cache/go-build diff --git a/docker/Dockerfile.node b/docker/Dockerfile.node new file mode 100644 index 0000000..0bade68 --- /dev/null +++ b/docker/Dockerfile.node @@ -0,0 +1,19 @@ +FROM --platform=${TARGETPLATFORM:-linux/amd64} jc21/nginx-full:${BASE_TAG:-latest} +LABEL maintainer="Jamie Curnow " + +ARG TARGETPLATFORM +RUN echo "Node: jc21/nginx-full:${BASE_TAG:-latest}, ${TARGETPLATFORM:-linux/amd64}" >> /built-for-arch + +ENV CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + +RUN curl -fsSL https://deb.nodesource.com/setup_15.x | bash - \ + && apt-get update \ + && apt-get install -y gcc make g++ git nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ + && npm install -g yarn + +# Check nodejs works on this architecture +COPY ./files/test.js /tmp/test.js +RUN node /tmp/test.js \ + && rm -f /tmp/test.js diff --git a/files/.bashrc b/files/.bashrc new file mode 100644 index 0000000..1a2f48d --- /dev/null +++ b/files/.bashrc @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ -t 1 ]; then + export PS1="\e[1;34m[\e[1;33m\u@\e[1;32mdocker-\h\e[1;37m:\w\[\e[1;34m]\e[1;36m\\$ \e[0m" +fi + +# Aliases +alias l='ls -lAsh --color' +alias ls='ls -C1 --color' +alias cp='cp -ip' +alias rm='rm -i' +alias mv='mv -i' +alias h='cd ~;clear;' + +echo -e -n '\E[1;34m' +figlet -w 120 "nginx-full" +echo -e "\E[1;36mOpenResty \E[1;32m${OPENRESTY_VERSION:-unknown}\E[1;36m, Kernel \E[1;32m$(uname -r)\E[0m" +echo -e -n '\E[1;34m' +cat /built-for-arch +echo -e -n '\E[0m' +echo diff --git a/files/test.js b/files/test.js new file mode 100644 index 0000000..0dc434f --- /dev/null +++ b/files/test.js @@ -0,0 +1,25 @@ +fs = require('fs'); + +tmpfile = '/tmp/nodejstest'; + +fs.writeFile(tmpfile, 'this is test data', function (err, data) { + if (err) { + console.error(err); + process.exit(1); + return; + } + + console.log('Wrote test file successfully'); + + // Delete file + try { + fs.unlinkSync(tmpfile) + } catch (err) { + console.error(err); + process.exit(1); + return; + } + + console.log('Removed test file successfully'); +}); + diff --git a/scripts/build-lua b/scripts/build-lua new file mode 100755 index 0000000..bcf5f5f --- /dev/null +++ b/scripts/build-lua @@ -0,0 +1,34 @@ +#!/bin/bash -e + +BLUE='\E[1;34m' +CYAN='\E[1;36m' +YELLOW='\E[1;33m' +GREEN='\E[1;32m' +RESET='\E[0m' + +echo -e "${BLUE}❯ ${CYAN}Building Lua ${YELLOW}${LUA_VERSION}...${RESET}" + +cd /tmp +wget "http://www.lua.org/ftp/lua-${LUA_VERSION}.tar.gz" +tar -xzf lua-${LUA_VERSION}.tar.gz +mv /tmp/lua-${LUA_VERSION} /tmp/lua +cd /tmp/lua + +make linux test +# We have to install Lua for the Luarocks build to succeed, it will be installed again when building the final image +make install + +echo -e "${BLUE}❯ ${GREEN}Lua build completed${RESET}" + +echo -e "${BLUE}❯ ${CYAN}Building Luarocks ${YELLOW}${LUAROCKS_VERSION}...${RESET}" + +cd /tmp +wget "http://luarocks.github.io/luarocks/releases/luarocks-${LUAROCKS_VERSION}.tar.gz" +tar -xzf luarocks-${LUAROCKS_VERSION}.tar.gz +mv /tmp/luarocks-${LUAROCKS_VERSION} /tmp/luarocks +cd /tmp/luarocks + +./configure +make + +echo -e "${BLUE}❯ ${GREEN}Luarocks build completed${RESET}" \ No newline at end of file diff --git a/scripts/build-openresty b/scripts/build-openresty new file mode 100755 index 0000000..3019542 --- /dev/null +++ b/scripts/build-openresty @@ -0,0 +1,59 @@ +#!/bin/bash -e + +BLUE='\E[1;34m' +CYAN='\E[1;36m' +YELLOW='\E[1;33m' +GREEN='\E[1;32m' +RESET='\E[0m' + +echo -e "${BLUE}❯ ${CYAN}Building OpenResty ${YELLOW}${OPENRESTY_VERSION}...${RESET}" + +cd /tmp +wget "https://openresty.org/download/openresty-${OPENRESTY_VERSION}.tar.gz" +tar -xzf openresty-${OPENRESTY_VERSION}.tar.gz +mv /tmp/openresty-${OPENRESTY_VERSION} /tmp/openresty +cd /tmp/openresty + +./configure \ + --prefix=/etc/nginx \ + --sbin-path=/usr/sbin/nginx \ + --modules-path=/usr/lib/nginx/modules \ + --conf-path=/etc/nginx/nginx.conf \ + --error-log-path=/var/log/nginx/error.log \ + --http-log-path=/var/log/nginx/access.log \ + --pid-path=/var/run/nginx.pid \ + --lock-path=/var/run/nginx.lock \ + --http-client-body-temp-path=/var/cache/nginx/client_temp \ + --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ + --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ + --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ + --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ + --user=nginx \ + --group=nginx \ + --with-compat \ + --with-threads \ + --with-http_addition_module \ + --with-http_auth_request_module \ + --with-http_dav_module \ + --with-http_flv_module \ + --with-http_gunzip_module \ + --with-http_gzip_static_module \ + --with-http_mp4_module \ + --with-http_random_index_module \ + --with-http_realip_module \ + --with-http_secure_link_module \ + --with-http_slice_module \ + --with-http_ssl_module \ + --with-http_stub_status_module \ + --with-http_sub_module \ + --with-http_v2_module \ + --with-mail \ + --with-mail_ssl_module \ + --with-stream \ + --with-stream_realip_module \ + --with-stream_ssl_module \ + --with-stream_ssl_preread_module + +make -j2 + +echo -e "${BLUE}❯ ${GREEN}OpenResty build completed${RESET}" diff --git a/scripts/buildx b/scripts/buildx new file mode 100755 index 0000000..b8ef22a --- /dev/null +++ b/scripts/buildx @@ -0,0 +1,31 @@ +#!/bin/bash -e + +BLUE='\E[1;34m' +CYAN='\E[1;36m' +YELLOW='\E[1;33m' +GREEN='\E[1;32m' +RESET='\E[0m' + +echo -e "${BLUE}❯ ${CYAN}Building docker multiarch: ${YELLOW}${*}${RESET}" + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "${DIR}/.." + +# Buildx Builder +docker buildx create --name "${BUILDX_NAME:-nginx-full}" || echo +docker buildx use "${BUILDX_NAME:-nginx-full}" + +docker buildx build \ + --platform linux/amd64,linux/arm64,linux/arm/7 \ + --progress plain \ + --pull \ + --build-arg BASE_TAG \ + --build-arg OPENRESTY_VERSION \ + --build-arg LUA_VERSION \ + --build-arg LUAROCKS_VERSION \ + $@ \ + . + +docker buildx rm "${BUILDX_NAME:-nginx-full}" + +echo -e "${BLUE}❯ ${GREEN}Multiarch build Complete${RESET}" diff --git a/scripts/install-lua b/scripts/install-lua new file mode 100755 index 0000000..1f467b1 --- /dev/null +++ b/scripts/install-lua @@ -0,0 +1,23 @@ +#!/bin/bash -e + +BLUE='\E[1;34m' +CYAN='\E[1;36m' +YELLOW='\E[1;33m' +GREEN='\E[1;32m' +RESET='\E[0m' + +echo -e "${BLUE}❯ ${CYAN}Installing Lua ${YELLOW}${LUA_VERSION}...${RESET}" + +cd /tmp/lua +make install +rm -rf /tmp/lua + +echo -e "${BLUE}❯ ${GREEN}Lua install completed${RESET}" + +echo -e "${BLUE}❯ ${CYAN}Installing Luarocks ${YELLOW}${LUAROCKS_VERSION}...${RESET}" + +cd /tmp/luarocks +make install +rm -rf /tmp/luarocks + +echo -e "${BLUE}❯ ${GREEN}Luarocks install completed${RESET}" \ No newline at end of file diff --git a/scripts/install-openresty b/scripts/install-openresty new file mode 100755 index 0000000..b0b0679 --- /dev/null +++ b/scripts/install-openresty @@ -0,0 +1,23 @@ +#!/bin/bash -e + +BLUE='\E[1;34m' +CYAN='\E[1;36m' +YELLOW='\E[1;33m' +GREEN='\E[1;32m' +RESET='\E[0m' + +echo -e "${BLUE}❯ ${CYAN}Installing OpenResty ${YELLOW}${OPENRESTY_VERSION}...${RESET}" + +cd /tmp/openresty +make install +rm -rf /tmp/openresty + +echo -e "${BLUE}❯ ${GREEN}OpenResty install completed${RESET}" + +echo -e "${BLUE}❯ ${CYAN}Installing OpenResty plugins...${RESET}" + +cd / +luarocks install lua-cjson +luarocks install lua-resty-openidc + +echo -e "${BLUE}❯ ${GREEN}OpenResty plugins install completed${RESET}"