在树莓派上搭建一个docker文档的镜像站

简介

众所周知,docker文档的网站访问时很慢的,如果你没有什么特殊的方法那么你的体验会很不好,而kubernetes文档的访问那就是不能访问,所以在自己本地搭建一个文档的镜像就显得很重要了,我树莓派上使用的是swarm集群,因为是树莓派,官方并没有提供arm的镜像,所以要自己编译,如果你本地和我一样只有一个树莓派或者8个树莓派组成的swarm集群,你可以看看我的这个文章

操作

首先说下我的操作,我是使用drone做的cicd去编译的镜像,这过程很曲折,但是好在最后我还是编译出来了,因为大部分镜像是没有arm版本的,所以我有一个想法,就是想创建一个arm的镜像仓库,然后方便大家去使用,废话不多说,直接操作

首先看下docker文档的镜像仓库

https://github.com/docker/docker.github.io

里面有一个dockerfile,我们所要做的就是把这个dockerfile编译成镜像,在此之前我们先看看他的基础镜像

FROM starefossen/github-pages:198 AS builderbase FROM scratch AS archives-false FROM scratch AS archives-true FROM archives-${ENABLE_ARCHIVES} AS archives FROM alpine AS upstream-resources FROM builderbase AS current FROM archives AS deploy-source FROM nginx:alpine AS deploy

里面除了starefossen/github-pages:198其实都是有arm镜像的,所以我们要编译starefossen/github-pages:198这个镜像为arm版本,所以我们要看这个镜像的repo

https://github.com/Starefossen/docker-github-pages

里面有个dockerfile,里面的基础镜像是

starefossen/ruby-node:2-6-alpine

所以在编译starefossen/github-pages:198之前我们要编译starefossen/ruby-node:2-6-alpine,所以我们再看starefossen/ruby-node:2-6-alpine的repo

https://github.com/Starefossen/docker-ruby-node

这个基础镜像的dockerfile在

https://github.com/Starefossen/docker-ruby-node/blob/master/2-6/alpine/Dockerfile

看下这个镜像的基础镜像是

FROM ruby:2-alpine

这个镜像是有arm版本的,所以我们先编译

starefossen/ruby-node:2-6-alpine

编译starefossen/ruby-node:2-6-alpine

首先他的dockerfile中有一些gpg验证是可以不用做的,如果加上会编译不成功,最终的dockerfile被我修改成了下面这个样子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
FROM ruby:2-alpine


ENV NODE_MAJOR 6

RUN addgroup -g 1000 node \
    && adduser -u 1000 -G node -s /bin/sh -D node \
    && apk add --no-cache \
        libstdc++ \
    && apk add --no-cache --virtual .build-deps \
        binutils-gold \
        curl \
        g++ \
        gcc \
        gnupg \
        libgcc \
        linux-headers \
        make \
        python \
    && NODE_VERSION=$(curl -SL "https://nodejs.org/dist/index.tab" \
      | grep "^v$NODE_MAJOR" \
      | head -n 1 | awk '{ print substr($1,2) }') \
    && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.xz" \
    && tar -xf "node-v$NODE_VERSION.tar.xz" \
    && cd "node-v$NODE_VERSION" \
    && ./configure \
    && make -j$(getconf _NPROCESSORS_ONLN) \
    && make install \
    && apk del .build-deps \
    && cd .. \
    && rm -Rf "node-v$NODE_VERSION" \
    && rm "node-v$NODE_VERSION.tar.xz"

RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
  && YARN_VERSION=$(curl -sSL --compressed https://yarnpkg.com/latest-version) \
  && curl -fSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
  && mkdir -p /opt/yarn \
  && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/yarn --strip-components=1 \
  && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -s /opt/yarn/bin/yarn /usr/local/bin/yarnpkg \
  && rm yarn-v$YARN_VERSION.tar.gz \
  && apk del .build-deps-yarn

具体的东西你可以和他的对比下就是少了文件下载验证的过程,之后编写.drone.yml,我的如下,其实就是一个使用docker插件的过程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
kind: pipeline
type: docker
name: ruby-node

workspace:
  path: /build/ruby-node

platform:
  os: linux
  arch: arm


steps:
- name: docker
  image: plugins/docker
  settings:
    repo: 10.10.100.12:5000/ruby-node
    tags: 2-6-alpine
    insecure: true
    registry: 10.10.100.12:5000
    custom_dns: 114.114.114.114
...

这里我就直接推送到我的本地仓库了,编译的时候因为树莓派性能的局限性可能会很慢,之间又碰到了几次坑,所以必须要有耐心

这样子编译完成之后我们编译

starefossen/github-pages:198

编译starefossen/github-pages:198

因为我们已经把上个镜像推送到仓库了,所以我们要修改dockerfile为下面这个样子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
FROM 10.10.100.12:5000/ruby-node:2-6-alpine

ENV GITHUB_GEM_VERSION 202
ENV JSON_GEM_VERSION 1.8.6

RUN apk --update add --virtual build_deps \
    build-base ruby-dev libc-dev linux-headers \
  && gem install --verbose --no-document \
    json:${JSON_GEM_VERSION} \
    github-pages:${GITHUB_GEM_VERSION} \
    jekyll-github-metadata \
    minitest \
  && apk del build_deps \
  && apk add git \
  && mkdir -p /usr/src/app \
  && rm -rf /usr/lib/ruby/gems/*/cache/*.gem

WORKDIR /usr/src/app

EXPOSE 4000 80
CMD jekyll serve -d /_site --watch --force_polling -H 0.0.0.0 -P 4000

就是修改了from字段

我的.drone.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
---
kind: pipeline
type: docker
name: github-pages

platform:
  os: linux
  arch: arm


steps:
- name: docker
  image: plugins/docker
  settings:
    repo: 10.10.100.12:5000/github-pages
    tags: 198
    insecure: true
    registry: 10.10.100.12:5000
    custom_dns: 114.114.114.114
...

这步一般会直接编译成功,注意,路由器最好直接fq,不然alpine apk update的时候可能会很慢

最后就是大头了,编译docker.github.io镜像

编译docker.github.io镜像

这里我们也是只要修改from字段就可以了,因为整个仓库是很大的,所以使用drone编译的时候clone就会很慢,我的dockerfile如下

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
# This Dockerfile builds the docs for https://docs.docker.com/
# from the master branch of https://github.com/docker/docker.github.io
#
# Here is the sequence:
# 1.  Set up base stages for building and deploying
# 2.  Collect and build the archived documentation
# 3.  Collect and build the reference documentation (from upstream resources)
# 4.  Build static HTML from the current branch
# 5.  Build the final image, combining the archives, reference docs, and
#     current version of the documentation
#
# When the image is run, it starts Nginx and serves the docs at port 4000


# Engine
ARG ENGINE_BRANCH="19.03"

# Distribution
ARG DISTRIBUTION_BRANCH="release/2.7"

# Set to "false" to build the documentation without archives
ARG ENABLE_ARCHIVES=true

###
# Set up base stages for building and deploying
###
FROM 10.10.100.12:5000/github-pages:198 AS builderbase
ENV TARGET=/usr/share/nginx/html
WORKDIR /usr/src/app/md_source/

# Set vars used by fetch-upstream-resources.sh script as an environment variable,
# so that they are persisted in the image for use in later stages.
ARG ENGINE_BRANCH
ENV ENGINE_BRANCH=${ENGINE_BRANCH}

ARG DISTRIBUTION_BRANCH
ENV DISTRIBUTION_BRANCH=${DISTRIBUTION_BRANCH}


# Empty stage if archives are disabled (ENABLE_ARCHIVES=false)
FROM scratch AS archives-false

# Stage with static HTML for all archives (ENABLE_ARCHIVES=true)
FROM scratch AS archives-true
ENV TARGET=/usr/share/nginx/html
# To add a new archive, add it here and ALSO edit _data/docsarchive/archives.yaml
# to add it to the drop-down
COPY --from=docs/docker.github.io:v17.06 ${TARGET} /
COPY --from=docs/docker.github.io:v18.03 ${TARGET} /
COPY --from=docs/docker.github.io:v18.09 ${TARGET} /

# Stage either with, or without archives, depending on ENABLE_ARCHIVES
FROM archives-${ENABLE_ARCHIVES} AS archives

# Fetch upstream resources (reference documentation)
# Only add the files that are needed to build these reference docs, so that these
# docs are only rebuilt if changes were made to ENGINE_BRANCH or DISTRIBUTION_BRANCH.
# Disable caching (docker build --no-cache) to force updating these docs.
FROM alpine AS upstream-resources
RUN apk add --no-cache subversion wget
WORKDIR /usr/src/app/md_source/
COPY ./_scripts/fetch-upstream-resources.sh ./_scripts/
ARG ENGINE_BRANCH
ARG DISTRIBUTION_BRANCH
RUN ./_scripts/fetch-upstream-resources.sh .


# Build the static HTML for the current docs.
# After building with jekyll, fix up some links, but don't touch the archives
FROM builderbase AS current
COPY . .
COPY --from=upstream-resources /usr/src/app/md_source/. ./
# substitute the "{site.latest_engine_api_version}" in the title for the latest
# API docs, based on the latest_engine_api_version parameter in _config.yml
RUN ./_scripts/update-api-toc.sh
RUN jekyll build -d ${TARGET} \
 && find ${TARGET} -type f -name '*.html' | grep -vE "v[0-9]+\." | while read i; do sed -i 's#href="https://docs.docker.com/#href="/#g' "$i"; done


# This stage only contains the generated files. It can be used to host the
# documentation on a non-containerised service (e.g. to deploy to an s3 bucket).
# When using BuildKit, use the '--output' option to build the files and to copy
# them to your local filesystem.
#
# To build current docs, including archives:
# DOCKER_BUILDKIT=1 docker build --target=deploy-source --output=./_site .
#
# To build without archives:
# DOCKER_BUILDKIT=1 docker build --target=deploy-source --build-arg ENABLE_ARCHIVES=false --output=./_site .
FROM archives AS deploy-source
COPY --from=current /usr/share/nginx/html /

# Final stage, which includes nginx, and, depending on ENABLE_ARCHIVES, either
# current docs and archived versions (ENABLE_ARCHIVES=true), or only the current
# docs (ENABLE_ARCHIVES=false).
#
# To build current docs, including archives:
# DOCKER_BUILDKIT=1 docker build -t docs .
#
# To build without archives:
# DOCKER_BUILDKIT=1 docker build -t docs --build-arg ENABLE_ARCHIVES=false .
FROM nginx:alpine AS deploy
ENV TARGET=/usr/share/nginx/html
WORKDIR $TARGET

COPY --from=archives / .
COPY --from=current  /usr/share/nginx/html .

# Configure NGINX
COPY _deploy/nginx/default.conf /etc/nginx/conf.d/default.conf
CMD echo -e "Docker docs are viewable at:\nhttp://0.0.0.0:4000"; exec nginx -g 'daemon off;'

我的.drone.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
kind: pipeline
type: docker
name: docker.github.io

workspace:
  path: /build/docker.github.io

platform:
  os: linux
  arch: arm


steps:
- name: docker
  image: plugins/docker
  settings:
    repo: 10.10.100.12:5000/docker.github.io
    tags: latest
    insecure: true
    registry: 10.10.100.12:5000
    custom_dns: 114.114.114.114
...

最后

最后我共享下我编译出来的镜像

docker pull bboysoul/docker.github.io:19.03

因为docker文档的内容比较大,所以整体会比较大

已运行的网址

docker.bboysoul.cn

欢迎关注我的博客 www.bboy.app

Have Fun