1. 目的

在做分布式项目过程中,用到了rocksdb做数据的永久化,在测试多个节点时,需要用到docker来完成部署,因此需要制作docker镜像。这篇文章记录了若干种制作docker镜像的方案,记录了踩坑的过程。

2.配置环境

系统环境

//golang版本
go version go1.19.2 darwin/arm64

// docker,docker-compose的环境
Client:
 Cloud integration: v1.0.29
 Version:           20.10.21
 API version:       1.41
 Go version:        go1.18.7
 Git commit:        baeda1f
 Built:             Tue Oct 25 18:01:18 2022
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Desktop 4.15.0 (93002)
 Engine:
  Version:          20.10.21
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.18.7
  Git commit:       3056208
  Built:            Tue Oct 25 17:59:41 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.6.10
  GitCommit:        770bd0108c32f3fb5c73ae1264f7e503fe7b2661
 runc:
  Version:          1.1.4
  GitCommit:        v1.1.4-0-g5fd4c4d
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Docker Compose version v2.13.0

//宿主机rocksdb配置
brew info rocksdb
==> rocksdb: stable 7.8.3 (bottled), HEAD
Embeddable, persistent key-value store for fast storage
https://rocksdb.org/
/opt/homebrew/Cellar/rocksdb/7.8.3 (143 files, 41.3MB) *
  Poured from bottle on 2022-12-20 at 18:19:18
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/rocksdb.rb
License: GPL-2.0-only or Apache-2.0

3.环境安装

需要安装golang、docker、rocksdb(mac可以直接homebrew安装,linux则须先clone再自行编译)

4. 编译镜像制作

值得一提的是,由于本机是mac,而程序运行需要跑在linux系统上,因此在本机编译linux可执行文件需要golang的交叉编译。

4.1 本机交叉编译

使用MacOs的朋友可以看一下下面的这个文章,这里面揭示了一些可能出现的问题,在一开始的时候我也曾经想过在本机交叉编译后,直接复制到运行用的镜像里,但是一切都是十分顺利,直到需要编译rocksdb的时候,homebrew下载的交叉编译工具(mac原生的库有些不支持,就如下面的链接里的一样),一直提示找不到rocksdb需要用到的几个依赖。

4.2 在docker镜像中编译

最后经过几个小时的试错,最终决定在docker镜像里编译,再复制到运行镜像中运行。我们需要用到俩个文件

Makefile
.PHONY: build clean docker-build

BINARY=main
GO_VER = 1.19
ALPINE_VER ?= 3.16
VER = 1.0
BUILD_CONTEXT=.

build:
	@echo "compiling code ..."
	CGO_CFLAGS="-I/usr/local/rocksdb/ -I/usr/include/" \
	CGO_LDFLAGS="-L/usr/local/rocksdb/lib -L/usr/lib -lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy -llz4 -lzstd -static -fpic" \
	go build 
	@echo "compiled successfully in $(BUILD_CONTEXT)/$(BINARY)"

docker-build : 
	@echo "Building Docker image ..."
	@docker build -f . \
		--build-arg GO_VER=$(GO_VER) \
		--build-arg ALPINE_VER=$(ALPINE_VER) \
		-t $(BINARY):$(VER) $(BUILD_CONTEXT)

clean:
	@if [ -f $(BINARY) ] ; then rm $(BUILD_CONTEXT)/$(BINARY) ; fi

dockerfile

ARG GO_VER
ARG ALPINE_VER

FROM alpine:${ALPINE_VER} as base
RUN apk add --no-cache tzdata

# FROM golang:${GO_VER}-alpine${ALPINE_VER} as golang
# RUN apk add --no-cache \
# 	bash \
# 	binutils-gold \
# 	gcc \
# 	git \
# 	make \
# 	musl-dev 
# RUN apk add --update --no-cache build-base linux-headers git cmake bash perl #wget mercurial g++ autoconf libgflags-dev cmake bash
# RUN apk add --update --no-cache zlib zlib-dev bzip2 bzip2-dev snappy snappy-dev lz4 lz4-dev zstd zstd-dev

# # installing latest gflags
# RUN cd /tmp && \
#     git clone https://github.com/gflags/gflags.git && \
#     cd gflags && \
#     mkdir build && \
#     cd build && \
#     cmake -DBUILD_SHARED_LIBS=1 -DGFLAGS_INSTALL_SHARED_LIBS=1 .. && \
#     make install && \
#     cd /tmp && \
#     rm -R /tmp/gflags/

# # Install Rocksdb
# RUN cd /tmp && \
    # git clone https://github.com/facebook/rocksdb.git && \
    # cd rocksdb && \
    # git checkout v7.8.3 && \
    # make shared_lib && \
    # mkdir -p /usr/local/rocksdb/lib && \
    # mkdir /usr/local/rocksdb/include && \
    # cp librocksdb.so* /usr/local/rocksdb/lib && \
    # cp /usr/local/rocksdb/lib/librocksdb.so* /usr/lib/ && \
    # cp -r include /usr/local/rocksdb/ && \
    # cp -r include/* /usr/include/ && \
    # rm -R /tmp/rocksdb/
FROM golang-rocksdb-sdk as golang
ADD . /src
WORKDIR /src
RUN make build 

FROM base
WORKDIR /apps
COPY --from=golang /src/main /apps
EXPOSE 8000

ENTRYPOINT ["/apps/main"]

在main.go文件下,执行make docker-build 。就能自动执行镜像。但是前提是,需要编译一个制作镜像用的镜像

我们需要一下指令

mkdir golang-rocksdb
cd golang-rocksdb
docker build -t golang-rocksdb .

编译以下docker镜像

# FROM alpine:3.16 as builder



# RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >>/etc/apk/repositories

# RUN apk add --update --no-cache build-base linux-headers git perl \
#   cmake bash zlib zlib-dev bzip2 bzip2-dev snappy snappy-dev lz4 lz4-dev \
#   zstd@testing zstd-dev@testing libtbb-dev@testing libtbb@testing


# RUN cd tmp && \
#     git clone https://github.com/gflags/gflags.git && \
#     cd gflags && \
#     mkdir build && \
#     cd build && \
#     cmake -DBUILD_SHARED_LIBS=1 -DGFLAGS_INSTALL_SHARED_LIBS=1 .. && \
#     make install && \
#     cd ../ \
#     rm -R gflags/

# RUN cd /tmp && \
#     git clone https://github.com/facebook/rocksdb.git && \
#     cd rocksdb && \
#     git checkout v7.8.3 && \
#     make static_lib && \
#     mkdir -p /usr/local/rocksdb/lib && \
#     mkdir /usr/local/rocksdb/include && \
#     cp librocksdb.so* /usr/local/rocksdb/lib && \
#     cp /usr/local/rocksdb/lib/librocksdb.so* /usr/lib/ && \
#     cp -r include /usr/local/rocksdb/ && \
#     cp -r include/* /usr/include/ && \
#     rm -R /tmp/rocksdb/



# FROM golang:1.19-alpine3.16

FROM golang:1.19-alpine3.16 as golang
RUN apk add --no-cache \
	bash \
	binutils-gold \
	gcc \
	git \
	make \
	musl-dev 
RUN echo "@testing http://dl-cdn.alpinelinux.org/alpine/edge/testing" >>/etc/apk/repositories && \
  apk add --update --no-cache pkgconfig tzdata ca-certificates gcc openssl cmake linux-headers \ 
  alpine-sdk build-base libc-dev musl-dev libstdc++ libsodium-dev perl \
  zlib zlib-static \
  snappy snappy-dev snappy-static \
  zstd@testing zstd-dev@testing zstd-static \
  bzip2 bzip2-dev bzip2-static \
  lz4 lz4-dev lz4-static \
  libtbb-dev@testing libtbb@testing

# installing latest gflags
RUN cd /tmp && \
    git clone https://github.com/gflags/gflags.git && \
    cd gflags && \
    mkdir build && \
    cd build && \
    cmake -DBUILD_SHARED_LIBS=1 -DGFLAGS_INSTALL_SHARED_LIBS=1 .. && \
    make install && \
    cd /tmp && \
    rm -R /tmp/gflags/

# Install Rocksdb
RUN cd /tmp && \
    git clone https://github.com/facebook/rocksdb.git && \
    cd rocksdb && \
    git checkout v7.8.3 && \
    make static_lib && \
    mkdir -p /usr/local/rocksdb/lib && \
    mkdir /usr/local/rocksdb/include && \
    cp librocksdb.* /usr/local/rocksdb/lib && \
    cp /usr/local/rocksdb/lib/librocksdb.* /usr/lib/ && \
    cp -r include /usr/local/rocksdb/ && \
    cp -r include/* /usr/include/ && \
    rm -R /tmp/rocksdb/


该代码是我从网上找到的dockerfile改过来的,因为网上所使用的原版的rocksdb是旧版的,一些目录不适配。

因此需要手动修改,这里选择了golang1.19,alpine3.6,截止至本文写作时间之前,alpine3.7已经出了,但是因为apk有些包没有更新(比如zstd),因此选择了一个更稳定的版本。

最后,编译完成是这样的。

自行编写docker-compose文件,就可以启动自己的服务了。