Enable Multiarch docker builds
parent
b9fea361c9
commit
6380bd32d7
|
@ -42,3 +42,5 @@ users_database.test.yml
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
.authelia-interrupt
|
.authelia-interrupt
|
||||||
|
|
||||||
|
qemu-*-static
|
60
.travis.yml
60
.travis.yml
|
@ -1,12 +1,22 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
required: sudo
|
required: sudo
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- '1.13'
|
- '1.13'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
- ntp
|
- ntp
|
||||||
- xvfb
|
- xvfb
|
||||||
addons:
|
|
||||||
|
before_script:
|
||||||
|
- export PATH=./cmd/authelia-scripts/:/tmp:$PATH
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- stage: test
|
||||||
|
addons:
|
||||||
chrome: stable
|
chrome: stable
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
|
@ -14,17 +24,35 @@ addons:
|
||||||
packages:
|
packages:
|
||||||
- libgif-dev
|
- libgif-dev
|
||||||
- google-chrome-stable
|
- google-chrome-stable
|
||||||
|
script:
|
||||||
before_script:
|
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
|
||||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
|
- nvm install v11 && nvm use v11 && npm i
|
||||||
- nvm install v11 && nvm use v11 && npm i
|
- source bootstrap.sh
|
||||||
script:
|
- authelia-scripts ci
|
||||||
- "source bootstrap.sh"
|
# TODO(c.michaud): publish built artifact on Github.
|
||||||
- "authelia-scripts ci"
|
- &build-images
|
||||||
after_success:
|
stage: build images
|
||||||
- "authelia-scripts docker publish"
|
env:
|
||||||
|
- ARCH=amd64
|
||||||
# TODO(c.michaud): publish built artifact on Github.
|
install: skip
|
||||||
|
script:
|
||||||
|
- while sleep 9m; do echo '===== Prevent build from terminating ====='; done &
|
||||||
|
- authelia-scripts docker build --arch=$ARCH
|
||||||
|
- kill %1
|
||||||
|
after_success:
|
||||||
|
- authelia-scripts docker push-image --arch=$ARCH
|
||||||
|
- <<: *build-images
|
||||||
|
env:
|
||||||
|
- ARCH=arm32v7
|
||||||
|
- <<: *build-images
|
||||||
|
env:
|
||||||
|
- ARCH=arm64v8
|
||||||
|
- stage: deploy manifests
|
||||||
|
env:
|
||||||
|
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
|
install: skip
|
||||||
|
script:
|
||||||
|
- authelia-scripts docker push-manifest
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
|
|
@ -10,7 +10,7 @@ WORKDIR /go/src/app
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||||
RUN cd cmd/authelia && GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o authelia
|
RUN cd cmd/authelia && GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags netgo -ldflags '-w' -o authelia
|
||||||
|
|
||||||
|
|
||||||
# ========================================
|
# ========================================
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# =======================================
|
||||||
|
# ===== Build image for the backend =====
|
||||||
|
# =======================================
|
||||||
|
FROM arm32v7/golang:1.13-alpine AS builder-backend
|
||||||
|
|
||||||
|
# qemu binary, gcc and musl-dev are required for building go-sqlite3
|
||||||
|
COPY ./qemu-arm-static /usr/bin/qemu-arm-static
|
||||||
|
RUN apk --no-cache add gcc musl-dev
|
||||||
|
|
||||||
|
WORKDIR /go/src/app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||||
|
RUN cd cmd/authelia && GOOS=linux GOARCH=arm CGO_ENABLED=1 go build -tags netgo -ldflags '-w' -o authelia
|
||||||
|
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# ===== Build image for the frontend =====
|
||||||
|
# ========================================
|
||||||
|
FROM node:11-alpine AS builder-frontend
|
||||||
|
|
||||||
|
WORKDIR /node/src/app
|
||||||
|
COPY client .
|
||||||
|
|
||||||
|
# Install the dependencies and build
|
||||||
|
RUN npm ci && npm run build
|
||||||
|
|
||||||
|
# ===================================
|
||||||
|
# ===== Authelia official image =====
|
||||||
|
# ===================================
|
||||||
|
FROM arm32v7/alpine:3.10.3
|
||||||
|
|
||||||
|
COPY ./qemu-arm-static /usr/bin/qemu-arm-static
|
||||||
|
|
||||||
|
RUN apk --no-cache add ca-certificates tzdata && \
|
||||||
|
rm /usr/bin/qemu-arm-static
|
||||||
|
|
||||||
|
WORKDIR /usr/app
|
||||||
|
|
||||||
|
COPY --from=builder-backend /go/src/app/cmd/authelia/authelia authelia
|
||||||
|
COPY --from=builder-frontend /node/src/app/build public_html
|
||||||
|
|
||||||
|
EXPOSE 9091
|
||||||
|
|
||||||
|
VOLUME /etc/authelia
|
||||||
|
VOLUME /var/lib/authelia
|
||||||
|
|
||||||
|
CMD ["./authelia", "-config", "/etc/authelia/config.yml"]
|
|
@ -0,0 +1,48 @@
|
||||||
|
# =======================================
|
||||||
|
# ===== Build image for the backend =====
|
||||||
|
# =======================================
|
||||||
|
FROM arm64v8/golang:1.13-alpine AS builder-backend
|
||||||
|
|
||||||
|
# qemu binary, gcc and musl-dev are required for building go-sqlite3
|
||||||
|
COPY ./qemu-aarch64-static /usr/bin/qemu-aarch64-static
|
||||||
|
RUN apk --no-cache add gcc musl-dev
|
||||||
|
|
||||||
|
WORKDIR /go/src/app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||||
|
RUN cd cmd/authelia && GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -tags netgo -ldflags '-w' -o authelia
|
||||||
|
|
||||||
|
|
||||||
|
# ========================================
|
||||||
|
# ===== Build image for the frontend =====
|
||||||
|
# ========================================
|
||||||
|
FROM node:11-alpine AS builder-frontend
|
||||||
|
|
||||||
|
WORKDIR /node/src/app
|
||||||
|
COPY client .
|
||||||
|
|
||||||
|
# Install the dependencies and build
|
||||||
|
RUN npm ci && npm run build
|
||||||
|
|
||||||
|
# ===================================
|
||||||
|
# ===== Authelia official image =====
|
||||||
|
# ===================================
|
||||||
|
FROM arm64v8/alpine:3.10.3
|
||||||
|
|
||||||
|
COPY ./qemu-aarch64-static /usr/bin/qemu-aarch64-static
|
||||||
|
|
||||||
|
RUN apk --no-cache add ca-certificates tzdata && \
|
||||||
|
rm /usr/bin/qemu-aarch64-static
|
||||||
|
|
||||||
|
WORKDIR /usr/app
|
||||||
|
|
||||||
|
COPY --from=builder-backend /go/src/app/cmd/authelia/authelia authelia
|
||||||
|
COPY --from=builder-frontend /node/src/app/build public_html
|
||||||
|
|
||||||
|
EXPOSE 9091
|
||||||
|
|
||||||
|
VOLUME /etc/authelia
|
||||||
|
VOLUME /var/lib/authelia
|
||||||
|
|
||||||
|
CMD ["./authelia", "-config", "/etc/authelia/config.yml"]
|
|
@ -94,7 +94,7 @@ func shell(cmd string) {
|
||||||
runCommand("bash", "-c", cmd)
|
runCommand("bash", "-c", cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildDockerImages() {
|
func buildHelperDockerImages() {
|
||||||
shell("docker build -t authelia-example-backend example/compose/nginx/backend")
|
shell("docker build -t authelia-example-backend example/compose/nginx/backend")
|
||||||
shell("docker build -t authelia-duo-api example/compose/duo-api")
|
shell("docker build -t authelia-duo-api example/compose/duo-api")
|
||||||
}
|
}
|
||||||
|
@ -210,8 +210,8 @@ func Bootstrap(cobraCmd *cobra.Command, args []string) {
|
||||||
installClientNpmPackages()
|
installClientNpmPackages()
|
||||||
|
|
||||||
bootstrapPrintln("Building development Docker images...")
|
bootstrapPrintln("Building development Docker images...")
|
||||||
buildDockerImages()
|
buildHelperDockerImages()
|
||||||
DockerBuildOfficialImage()
|
dockerBuildOfficialImage(defaultArch)
|
||||||
|
|
||||||
bootstrapPrintln("Installing Kubernetes dependencies for testing in /tmp... (no junk installed on host)")
|
bootstrapPrintln("Installing Kubernetes dependencies for testing in /tmp... (no junk installed on host)")
|
||||||
installKubernetesDependencies()
|
installKubernetesDependencies()
|
||||||
|
|
|
@ -41,14 +41,6 @@ func RunCI(cmd *cobra.Command, args []string) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("===== Docker image build stage =====")
|
|
||||||
command = CommandWithStdout("authelia-scripts", "docker", "build")
|
|
||||||
err = command.Run()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("===== End-to-end testing stage =====")
|
fmt.Println("===== End-to-end testing stage =====")
|
||||||
command = CommandWithStdout("authelia-scripts", "suites", "test", "--headless", "--only-forbidden")
|
command = CommandWithStdout("authelia-scripts", "suites", "test", "--headless", "--only-forbidden")
|
||||||
err = command.Run()
|
err = command.Run()
|
||||||
|
|
|
@ -5,13 +5,67 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DockerBuildOfficialImage() error {
|
var arch string
|
||||||
|
var supportedArch = []string{"amd64", "arm32v7", "arm64v8"}
|
||||||
|
var defaultArch = "amd64"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
DockerBuildCmd.PersistentFlags().StringVar(&arch, "arch", defaultArch, "target architecture among: "+strings.Join(supportedArch, ", "))
|
||||||
|
DockerPushCmd.PersistentFlags().StringVar(&arch, "arch", defaultArch, "target architecture among: "+strings.Join(supportedArch, ", "))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkArchIsSupported(arch string) {
|
||||||
|
for _, a := range supportedArch {
|
||||||
|
if arch == a {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Fatal("Architecture is not supported. Please select one of " + strings.Join(supportedArch, ", ") + ".")
|
||||||
|
}
|
||||||
|
|
||||||
|
func dockerBuildOfficialImage(arch string) error {
|
||||||
docker := &Docker{}
|
docker := &Docker{}
|
||||||
return docker.Build(IntermediateDockerImageName, ".")
|
// Set default Architecture Dockerfile to amd64
|
||||||
|
dockerfile := "Dockerfile"
|
||||||
|
|
||||||
|
// If not the default value
|
||||||
|
if arch != defaultArch {
|
||||||
|
dockerfile = fmt.Sprintf("%s.%s", dockerfile, arch)
|
||||||
|
}
|
||||||
|
|
||||||
|
if arch == "arm32v7" {
|
||||||
|
err := CommandWithStdout("docker", "run", "--rm", "--privileged", "multiarch/qemu-user-static", "--reset", "-p", "yes").Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CommandWithStdout("bash", "-c", "wget https://github.com/multiarch/qemu-user-static/releases/download/v4.1.0-1/qemu-arm-static -O ./qemu-arm-static && chmod +x ./qemu-arm-static").Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else if arch == "arm64v8" {
|
||||||
|
err := CommandWithStdout("docker", "run", "--rm", "--privileged", "multiarch/qemu-user-static", "--reset", "-p", "yes").Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CommandWithStdout("bash", "-c", "wget https://github.com/multiarch/qemu-user-static/releases/download/v4.1.0-1/qemu-aarch64-static -O ./qemu-aarch64-static && chmod +x ./qemu-aarch64-static").Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return docker.Build(IntermediateDockerImageName, dockerfile, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
// DockerBuildCmd Command for building docker image of Authelia.
|
// DockerBuildCmd Command for building docker image of Authelia.
|
||||||
|
@ -19,7 +73,8 @@ var DockerBuildCmd = &cobra.Command{
|
||||||
Use: "build",
|
Use: "build",
|
||||||
Short: "Build the docker image of Authelia",
|
Short: "Build the docker image of Authelia",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := DockerBuildOfficialImage()
|
checkArchIsSupported(arch)
|
||||||
|
err := dockerBuildOfficialImage(arch)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -36,10 +91,20 @@ var DockerBuildCmd = &cobra.Command{
|
||||||
|
|
||||||
// DockerPushCmd Command for pushing Authelia docker image to Dockerhub
|
// DockerPushCmd Command for pushing Authelia docker image to Dockerhub
|
||||||
var DockerPushCmd = &cobra.Command{
|
var DockerPushCmd = &cobra.Command{
|
||||||
Use: "publish",
|
Use: "push-image",
|
||||||
Short: "Publish Authelia docker image to Dockerhub",
|
Short: "Publish Authelia docker image to Dockerhub",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
publishDockerImage()
|
checkArchIsSupported(arch)
|
||||||
|
publishDockerImage(arch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// DockerManifestCmd Command for pushing Authelia docker manifest to Dockerhub
|
||||||
|
var DockerManifestCmd = &cobra.Command{
|
||||||
|
Use: "push-manifest",
|
||||||
|
Short: "Publish Authelia docker manifest to Dockerhub",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
publishDockerManifest()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,14 +141,33 @@ func deploy(docker *Docker, tag string) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
docker.Push(imageWithTag)
|
err = docker.Push(imageWithTag)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func publishDockerImage() {
|
func deployManifest(docker *Docker, tag string, amd64tag string, arm32v7tag string, arm64v8tag string) {
|
||||||
|
imageWithTag := DockerImageName + ":" + tag
|
||||||
|
fmt.Println("===================================================")
|
||||||
|
fmt.Println("Docker manifest " + imageWithTag + " will be deployed on Dockerhub.")
|
||||||
|
fmt.Println("===================================================")
|
||||||
|
|
||||||
|
err := docker.Tag(DockerImageName, imageWithTag)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = docker.Manifest(imageWithTag, amd64tag, arm32v7tag, arm64v8tag)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func publishDockerImage(arch string) {
|
||||||
docker := &Docker{}
|
docker := &Docker{}
|
||||||
|
|
||||||
travisBranch := os.Getenv("TRAVIS_BRANCH")
|
travisBranch := os.Getenv("TRAVIS_BRANCH")
|
||||||
|
@ -92,12 +176,31 @@ func publishDockerImage() {
|
||||||
|
|
||||||
if travisBranch == "master" && travisPullRequest == "false" {
|
if travisBranch == "master" && travisPullRequest == "false" {
|
||||||
login(docker)
|
login(docker)
|
||||||
deploy(docker, "master")
|
deploy(docker, "master-"+arch)
|
||||||
} else if travisTag != "" {
|
} else if travisTag != "" {
|
||||||
login(docker)
|
login(docker)
|
||||||
deploy(docker, travisTag)
|
deploy(docker, travisTag+"-"+arch)
|
||||||
deploy(docker, "latest")
|
deploy(docker, "latest-"+arch)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Docker image will not be built")
|
fmt.Println("Docker image will not be published")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func publishDockerManifest() {
|
||||||
|
docker := &Docker{}
|
||||||
|
|
||||||
|
travisBranch := os.Getenv("TRAVIS_BRANCH")
|
||||||
|
travisPullRequest := os.Getenv("TRAVIS_PULL_REQUEST")
|
||||||
|
travisTag := os.Getenv("TRAVIS_TAG")
|
||||||
|
|
||||||
|
if travisBranch == "master" && travisPullRequest == "false" {
|
||||||
|
login(docker)
|
||||||
|
deployManifest(docker, "master", "master-amd64", "master-arm32v7", "master-arm64v8")
|
||||||
|
} else if travisTag != "" {
|
||||||
|
login(docker)
|
||||||
|
deployManifest(docker, travisTag, travisTag+"-amd64", travisTag+"-arm32v7", travisTag+"-arm64v8")
|
||||||
|
deployManifest(docker, "latest", "latest-amd64", "latest-arm32v7", "latest-arm64v8")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Docker manifest will not be published")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ package main
|
||||||
type Docker struct{}
|
type Docker struct{}
|
||||||
|
|
||||||
// Build build a docker image
|
// Build build a docker image
|
||||||
func (d *Docker) Build(tag string, target string) error {
|
func (d *Docker) Build(tag string, dockerfile string, target string) error {
|
||||||
return CommandWithStdout("docker", "build", "-t", tag, target).Run()
|
return CommandWithStdout("docker", "build", "-t", tag, "-f", dockerfile, target).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag tag a docker image.
|
// Tag tag a docker image.
|
||||||
|
@ -22,3 +22,26 @@ func (d *Docker) Login(username, password string) error {
|
||||||
func (d *Docker) Push(tag string) error {
|
func (d *Docker) Push(tag string) error {
|
||||||
return CommandWithStdout("docker", "push", tag).Run()
|
return CommandWithStdout("docker", "push", tag).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manifest push a docker manifest to dockerhub.
|
||||||
|
func (d *Docker) Manifest(tag string, amd64tag string, arm32v7tag string, arm64v8tag string) error {
|
||||||
|
err := CommandWithStdout("docker", "manifest", "create", tag, amd64tag, arm32v7tag, arm64v8tag).Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CommandWithStdout("docker", "manifest", "annotate", tag, arm32v7tag, "--os", "linux", "--arch", "arm").Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = CommandWithStdout("docker", "manifest", "annotate", tag, arm64v8tag, "--os", "linux", "--arch", "arm64", "--variant", "v8").Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CommandWithStdout("docker", "manifest", "push", "--purge", tag).Run()
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ var Commands = []AutheliaCommandDefinition{
|
||||||
AutheliaCommandDefinition{
|
AutheliaCommandDefinition{
|
||||||
Name: "docker",
|
Name: "docker",
|
||||||
Short: "Commands related to building and publishing docker image",
|
Short: "Commands related to building and publishing docker image",
|
||||||
SubCommands: CobraCommands{DockerBuildCmd, DockerPushCmd},
|
SubCommands: CobraCommands{DockerBuildCmd, DockerPushCmd, DockerManifestCmd},
|
||||||
},
|
},
|
||||||
AutheliaCommandDefinition{
|
AutheliaCommandDefinition{
|
||||||
Name: "hash-password [password]",
|
Name: "hash-password [password]",
|
||||||
|
|
Loading…
Reference in New Issue