Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include liblsquic build in dockerfile + add support for ARM64 on Docker #2147

Merged
merged 3 commits into from
Jul 15, 2021
Merged

Include liblsquic build in dockerfile + add support for ARM64 on Docker #2147

merged 3 commits into from
Jul 15, 2021

Conversation

nemunaire
Copy link
Contributor

@nemunaire nemunaire commented Jun 12, 2021

Close #361


Hi,

This pull request is an attempt to resolve #361.

First, instead of relying on the static built liblsquic from https://github.com/iv-org/lsquic-static-alpine, it builds it as a first step. It works both for amd64, arm and arm64.

Secondly, instead of using crystallang/crystal:1.0.0-alpine, which is only available for amd64, it uses alpine:edge, as there are crystal-1.0.0 for both amd64 and arm64, but not for arm.

So thanks to this PR, Docker image can be built for amd64 and arm64, but not arm (v6 nor v7, because alpine doesn't provide a package for it, and I don't find any Docker image for crystal-1.0.0).

All this work was done thanks to @omarroth instructions and its archived repositories.

I have been using Invidious since a few month now on a Pine64 board with 2GB of RAM, and it works fine (but 2GB is not sufficient to build it). Here is a arm64 only image that I built with the exact commit of this PR: https://hub.docker.com/r/nemunaire/invidious

@unixfox
Copy link
Member

unixfox commented Jun 12, 2021

I'm not going to lie, using APKBUILD in order to build lsquic and boringssl is a very clever idea. Kudos to you.

The only issue with alpine:edge is that we don't track a specific crystal version and if one day crystal decide to release a new version, alpine will also update the crystal package. This could then render the Docker image broken because most of the time a new version of crystal will break the Invidious code.
I thought we could force to a specific version like explained here but it seems like this won't work, I tried with a previous version of crystal:

alpine:~# apk add crystal=0.35.1-r0
ERROR: unable to select packages:
  crystal-1.0.0-r0:
    breaks: world[crystal=0.35.1-r0]

Or we can build our own crystal Docker image for aarch64 but this seems to be a very complicated task from what I tried a couple of days ago.

Apart from this issue, I think it's a great idea to build lsquic directly into the Dockerfile. In fact I still up to this day don't understand why lsquic-static-alpine was created because we can utilize the Docker cache layer and just build lsquic once.

@unixfox
Copy link
Member

unixfox commented Jun 12, 2021

After testing this PR, on an ARMv8 and x86 device, Invidious will crash when the client load a URL from the videoplayback endpoint. This is easily reproducible by enabling dash or enabling proxy videos.

The error message is this one on an ARMv8 device:

invidious_1  | [development] Kemal is ready to lead at http://0.0.0.0:3000
invidious_1  | 2021-06-12 17:39:43 UTC [info] 200 GET /watch?v=9mm0KO4ipXo 5.52ms
invidious_1  | 2021-06-12 17:39:43 UTC [info] 302 GET /latest_version?id=9mm0KO4ipXo&itag=18 3.39ms
invidious_1  | 2021-06-12 17:39:43 UTC [info] 200 GET /api/manifest/dash/id/9mm0KO4ipXo?local=true&unique_res=1 4.73ms
invidious_1  | 2021-06-12 17:39:43 UTC [info] 200 GET /api/v1/storyboards/9mm0KO4ipXo?height=90 3.63ms
invidious_1  | 2021-06-12 17:39:43 UTC [info] 200 GET /favicon-32x32.png?v=f529948 248.4µs
invidious_1  | Invalid memory access (signal 11) at address 0x10000001b
invidious_1  | [0x69b480] ???
invidious_1  | [0x41a5e0] ???
invidious_1  | [0xf7e8a4] ???
invidious_1  | [0xd668b8] ???
invidious_1  | [0xce9ad8] ???
invidious_1  | [0xd6ba80] ???
invidious_1  | [0xd6c090] ???
invidious_1  | [0x9058ac] ???
invidious_1  | [0x905784] ???
invidious_1  | [0x9b1174] ???
invidious_1  | [0x9b088c] ???
invidious_1  | [0x9b0804] ???
invidious_1  | [0x9b05f0] ???
invidious_1  | [0x9b035c] ???
invidious_1  | [0x9b1e14] ???
invidious_1  | [0x9b1f10] ???
invidious_1  | [0x62744c] ???
invidious_1  | [0x493504] ???
invidious_1  | [0x84f9c0] ???
invidious_1  | [0x84f93c] ???
invidious_1  | [0x8551e4] ???
invidious_1  | [0x854b48] ???
invidious_1  | [0x848114] ???
invidious_1  | [0x847b9c] ???
invidious_1  | [0x87c3fc] ???
invidious_1  | [0x87c000] ???
invidious_1  | [0x87aab4] ???
invidious_1  | [0x8796e8] ???
invidious_1  | [0x87bcb4] ???
invidious_1  | [0x87adb8] ???
invidious_1  | [0x879394] ???
invidious_1  | [0x878dd4] ???
invidious_1  | [0xbbadb4] ???
invidious_1  | [0xbb9cd8] ???
invidious_1  | [0x87836c] ???
invidious_1  | [0x877f80] ???
invidious_1  | [0x92f314] ???
invidious_1  | [0x92ef50] ???
invidious_1  | [0x84e7ec] ???
invidious_1  | [0x84e590] ???
invidious_1  | [0xbc4060] ???
invidious_1  | [0xbc2c28] ???
invidious_1  | [0x68a9cc] ???
invidious_1  | [0x7432b8] ???
invidious_1  | [0x419af4] ???
invidious_1  | [0x0] ???

And on an x86 device:

invidious_1  | [development] Kemal is ready to lead at http://0.0.0.0:3000
invidious_1  | 2021-06-12 18:15:02 UTC [info] 200 GET /vi/gixrVIblEbc/mqdefault.jpg 281.45ms
invidious_1  | 2021-06-12 18:15:02 UTC [info] 200 GET /vi/W57EKdp3nf8/mqdefault.jpg 292.29ms
invidious_1  | 2021-06-12 18:15:02 UTC [info] 200 GET /api/manifest/dash/id/hK6A_ebUKrM?local=true&unique_res=1 7.84ms
invidious_1  | 2021-06-12 18:15:02 UTC [info] 200 GET /api/v1/storyboards/hK6A_ebUKrM?height=90 6.44ms
invidious_1  | Invalid memory access (signal 11) at address 0x10000001b
invidious_1  | [0x7abbb6] ???
invidious_1  | [0x41dedc] ???
invidious_1  | [0x129c1b8] ???

This is related to the internal HTTP client of crystal because turning off QUIC with use_quic: false will instantly produce the error.

Not sure how to solve this issue nor what's really causing this issue.

@nemunaire
Copy link
Contributor Author

Perhaps the next alpine 3.14 will have crystal-1.0 and we can rely on the version stability. But the real solution is crystal publishing containers for arm and arm64.

Meanwhile, we could just pick the liblsquic build, with crystallang/crystal:1.0.0-alpine.

I got the same error, when using use_quic: false. I think this is due to a conflict between openssl and boringssl, when building Invidious, I prepare a replacement Dockerfile.

@nemunaire
Copy link
Contributor Author

From what I understand, in the previous Dockerfile, Invidious was compiled with boringssl instead of openssl. However, only liblsquic needs boringssl. So I move the end of the build of liblsquic.a in the first part of the Dockerfile. This fixes the internal HTTP client problems.

In this second patch, I also keep using crystallang/crystal:1.0.0-alpine. For arm64 build, I create another branch that makes use of alpine:edge, but as we discuss, this'll not work reliably in the future, as we can't choose the crystal version to use: it'll always be the latest.

@unixfox
Copy link
Member

unixfox commented Jun 12, 2021

Thank you for fixing this issue, it is now indeed working perfectly on both arm64 and x86. I think until Alpine 3.14 comes out with crystal 1.0.0 you can publish the arm64 Dockerfile under the file name Dockerfile.arm64.

When I've some free time, I'll work to automatically build the arm64 docker image using GitHub actions and Docker buildx. You may also try to work on it if you have some free time too.

EDIT: I'm converting this PR to a draft for the moment until we have automated the build of the ARM64 docker image.

@unixfox unixfox marked this pull request as draft June 12, 2021 22:39
@nemunaire
Copy link
Contributor Author

nemunaire commented Jun 13, 2021

I tried lots of thinks but none of them are working 😞

I didn't find sufficient documentation about existing variable to change the file depending on the target platform. It seems to not be possible to do this, because it is the way docker buildx work.

To use buildx, we have to split the build process between arm64 and amd64:

      - name: Build andpush forPush Event (amd64)
        if: github.ref = 'refs/heads/master'
        uses: docker/build-push-action@v2
        with:
          context: .
          platforms: linux/amd64
          file: docker/Dockerfile
          labels: quay.expires-after=12w
          push: true
          tags: quay.io/invidious/invidious:${{github.sha}},quay.io/invidious/invidious:latest
      - name: Build andpush forPush Event (arm64)
        if: github.ref = 'refs/heads/master'
        uses: docker/build-push-action@v2
        with:
          context: .
          platforms: linux/arm64
          file: docker/Dockerfile.arm64
          labels: quay.expires-after=12w
          push: true
          tags: quay.io/invidious/invidious:${{github.sha}}-arm64,quay.io/invidious/invidious:latest-arm64

This is not very convinient as we can't make docker run .../invidious on arm64 the same way we can do it on amd64, we need to suffix with :xx-arm64.

I tried with a common image Dockerfile.buildx which includes:

#Define the FROM imagedepending on the target arch
ARG TARGETPLATFORM
ENV CRYSTALBUILDER="${TARGETPLATFORM/linux\/amd64/crystallang\/crystal:1.0.0-alpine}"
ENV CRYSTALBUILDER="${CRYSTALBUILDER:-alpine:edge}"

FROM $CRYSTALBUILDER AS builder
RUN if ["${CRYSTALBUILDER}" = "alpine:edge" ]; then \
        apk add --no-cache 'crystal<2' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev; \
    else \
        apk add --no-cache sqlite-static yaml-static; \
    fi

But it didn't work because there is no such variable substitution in ENV.

The legacy way is to create invidious:${{github.sha}}-arm64 and invidious:${{github.sha}}-amd64, then to merge them under invidious:${{github.sha}}. Such tool exists with DroneCI, but I don't find equivalent in GitHub actions.

I am short of solutions now. If you have any advise to continue, I'll take it!

@unixfox
Copy link
Member

unixfox commented Jun 13, 2021

Thanks for trying to make GitHub actions working for ARM.

What about building both of the two Docker images with buildx for the same Docker tag latest and with push: false then push both of the docker images for the same tag? Not sure if that would combine the two Docker image into the same tag.

I was also thinking that if buildx doesn't allow to do that, we could instead build the ARM docker image with a normal docker build but using qemu-user-static. Maybe a classic docker build would allow us to do more advanced things.

Anyway, if it's not possible to combine the two docker image into one, then having two separate tags is fine for the moment.

@cgmastertecnology
Copy link

i got error at line 45

There is an error in the yaml syntax: YAMLSyntaxError: Document contains trailing content not separated by a ... or --- line

@unixfox
Copy link
Member

unixfox commented Jun 19, 2021

i got error at line 45

There is an error in the yaml syntax: YAMLSyntaxError: Document contains trailing content not separated by a ... or --- line

This PR is not really ready yet but could you explain a bit more how you got this error? While browsing to which page of invidious?

@unixfox
Copy link
Member

unixfox commented Jun 29, 2021

Alpine 3.14 just released: https://pkgs.alpinelinux.org/packages?name=crystal&branch=v3.14. I still want to have two different Docker images because I prefer to keep relying on the official crystal Docker image that we know work well for x86. If after a couple of months, the ARM docker image is stable, we can think of moving to a custom Docker image for the x86 Docker image.

@unixfox unixfox marked this pull request as ready for review July 15, 2021 21:36
@unixfox unixfox added the in-testing This feature has been deployed and is being tested label Jul 15, 2021
@unixfox unixfox changed the title Include liblsquic build in dockerfile Include liblsquic build in dockerfile + add support for ARM64 on Docker Jul 15, 2021
@unixfox unixfox merged commit aa3608f into iv-org:master Jul 15, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
in-testing This feature has been deployed and is being tested
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Request: Docker image based on Alpine (for ARM64)
3 participants