Enable Multiarch docker builds
parent
b9fea361c9
commit
6380bd32d7
|
@ -42,3 +42,5 @@ users_database.test.yml
|
|||
.idea
|
||||
|
||||
.authelia-interrupt
|
||||
|
||||
qemu-*-static
|
60
.travis.yml
60
.travis.yml
|
@ -1,12 +1,22 @@
|
|||
language: go
|
||||
|
||||
required: sudo
|
||||
|
||||
go:
|
||||
- '1.13'
|
||||
- '1.13'
|
||||
|
||||
services:
|
||||
- docker
|
||||
- ntp
|
||||
- xvfb
|
||||
addons:
|
||||
- docker
|
||||
- ntp
|
||||
- xvfb
|
||||
|
||||
before_script:
|
||||
- export PATH=./cmd/authelia-scripts/:/tmp:$PATH
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
addons:
|
||||
chrome: stable
|
||||
apt:
|
||||
sources:
|
||||
|
@ -14,17 +24,35 @@ addons:
|
|||
packages:
|
||||
- libgif-dev
|
||||
- google-chrome-stable
|
||||
|
||||
before_script:
|
||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
|
||||
- nvm install v11 && nvm use v11 && npm i
|
||||
script:
|
||||
- "source bootstrap.sh"
|
||||
- "authelia-scripts ci"
|
||||
after_success:
|
||||
- "authelia-scripts docker publish"
|
||||
|
||||
# TODO(c.michaud): publish built artifact on Github.
|
||||
script:
|
||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
|
||||
- nvm install v11 && nvm use v11 && npm i
|
||||
- source bootstrap.sh
|
||||
- authelia-scripts ci
|
||||
# TODO(c.michaud): publish built artifact on Github.
|
||||
- &build-images
|
||||
stage: build images
|
||||
env:
|
||||
- ARCH=amd64
|
||||
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:
|
||||
email:
|
||||
|
|
|
@ -10,7 +10,7 @@ WORKDIR /go/src/app
|
|||
COPY . .
|
||||
|
||||
# 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)
|
||||
}
|
||||
|
||||
func buildDockerImages() {
|
||||
func buildHelperDockerImages() {
|
||||
shell("docker build -t authelia-example-backend example/compose/nginx/backend")
|
||||
shell("docker build -t authelia-duo-api example/compose/duo-api")
|
||||
}
|
||||
|
@ -210,8 +210,8 @@ func Bootstrap(cobraCmd *cobra.Command, args []string) {
|
|||
installClientNpmPackages()
|
||||
|
||||
bootstrapPrintln("Building development Docker images...")
|
||||
buildDockerImages()
|
||||
DockerBuildOfficialImage()
|
||||
buildHelperDockerImages()
|
||||
dockerBuildOfficialImage(defaultArch)
|
||||
|
||||
bootstrapPrintln("Installing Kubernetes dependencies for testing in /tmp... (no junk installed on host)")
|
||||
installKubernetesDependencies()
|
||||
|
|
|
@ -41,14 +41,6 @@ func RunCI(cmd *cobra.Command, args []string) {
|
|||
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 =====")
|
||||
command = CommandWithStdout("authelia-scripts", "suites", "test", "--headless", "--only-forbidden")
|
||||
err = command.Run()
|
||||
|
|
|
@ -5,13 +5,67 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"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{}
|
||||
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.
|
||||
|
@ -19,7 +73,8 @@ var DockerBuildCmd = &cobra.Command{
|
|||
Use: "build",
|
||||
Short: "Build the docker image of Authelia",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := DockerBuildOfficialImage()
|
||||
checkArchIsSupported(arch)
|
||||
err := dockerBuildOfficialImage(arch)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -36,10 +91,20 @@ var DockerBuildCmd = &cobra.Command{
|
|||
|
||||
// DockerPushCmd Command for pushing Authelia docker image to Dockerhub
|
||||
var DockerPushCmd = &cobra.Command{
|
||||
Use: "publish",
|
||||
Use: "push-image",
|
||||
Short: "Publish Authelia docker image to Dockerhub",
|
||||
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)
|
||||
}
|
||||
|
||||
docker.Push(imageWithTag)
|
||||
err = docker.Push(imageWithTag)
|
||||
|
||||
if err != nil {
|
||||
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{}
|
||||
|
||||
travisBranch := os.Getenv("TRAVIS_BRANCH")
|
||||
|
@ -92,12 +176,31 @@ func publishDockerImage() {
|
|||
|
||||
if travisBranch == "master" && travisPullRequest == "false" {
|
||||
login(docker)
|
||||
deploy(docker, "master")
|
||||
deploy(docker, "master-"+arch)
|
||||
} else if travisTag != "" {
|
||||
login(docker)
|
||||
deploy(docker, travisTag)
|
||||
deploy(docker, "latest")
|
||||
deploy(docker, travisTag+"-"+arch)
|
||||
deploy(docker, "latest-"+arch)
|
||||
} 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{}
|
||||
|
||||
// Build build a docker image
|
||||
func (d *Docker) Build(tag string, target string) error {
|
||||
return CommandWithStdout("docker", "build", "-t", tag, target).Run()
|
||||
func (d *Docker) Build(tag string, dockerfile string, target string) error {
|
||||
return CommandWithStdout("docker", "build", "-t", tag, "-f", dockerfile, target).Run()
|
||||
}
|
||||
|
||||
// Tag tag a docker image.
|
||||
|
@ -22,3 +22,26 @@ func (d *Docker) Login(username, password string) error {
|
|||
func (d *Docker) Push(tag string) error {
|
||||
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{
|
||||
Name: "docker",
|
||||
Short: "Commands related to building and publishing docker image",
|
||||
SubCommands: CobraCommands{DockerBuildCmd, DockerPushCmd},
|
||||
SubCommands: CobraCommands{DockerBuildCmd, DockerPushCmd, DockerManifestCmd},
|
||||
},
|
||||
AutheliaCommandDefinition{
|
||||
Name: "hash-password [password]",
|
||||
|
|
Loading…
Reference in New Issue