在上一篇关于 OpenFaaS 函数的博客文章中,我们探讨了我们可以用 OpenFaaS 做什么 - 我们在 Golang 中创建了我们的第一个 OpenFaaS 函数,我们为它编写了单元测试,使用 Travis 设置 CI/CD 并使用 Taskfile 自动执行常见任务。现在,是时候深入一点了。
在这篇博文中,我们将研究如何构建自定义模板、优化它们、从它们构建函数,最后,我们还将 Go 模块合并到我们的新模板中。所以,让我们去做吧!
TL;DR:这篇文章的完整源代码,包括文档可以在这里找到:https://github.com/MartinHeinz/openfaas-templates
深入了解模板
如果我们想构建自定义模板,那么我们首先需要了解它们是如何工作的。我们先来看看模板由哪些文件组成:
template.ymllanguagepackagesfprocessmain.goindex.pyindex.jshandler.{go,js,py...}package.jsongo.modDockerfileDockerfile
watchdogof-watchdog
watchdogstdinstdout
[](https://res.cloudinary.com/practicaldev/image/fetch/s--TJDjoM-O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary. com/martinheinz/image/upload/v1574790497/blog_posts/watchdog-forking_vgd2d6.png)
of-watchdog
以上图片取自 OpenFaaS 架构文档:https://docs.openfaas.com/architecture/watchdog/
watchdog
创建模板
首先,模板具有特定的文件/目录结构,我们需要遵循它,它的外观是这样的:
template
└── my-template
├── Dockerfile
├── function
│ └── handler.go
├── main.go
└── template.yml
templatemy-template
watchdoggo
template
~ $ cd template/go
template/go $ ls -la
...
-rw-rw-r-- 1 martin martin 1173 nov 23 09:21 Dockerfile <- We need this to build it
...
template/go $ docker build -t martinheinz/go .
Sending build context to Docker daemon 7.168kB
...
Successfully built 586fd7a36c0c
Successfully tagged martinheinz/go:latest
看起来不错,现在让我们部署功能,好吗?
~ $ docker push martinheinz/go:latest
~ $ faas-cli deploy --image=martinheinz/go:latest --name=go-test-func
~ $ echo "It's Working!" | faas-cli invoke go-test-func
Hello, Go. You said: It's Working!
dockerfaas-cli buildfaas-cli push
我们可以改进什么?
上一节中的 classic 模板非常好,但它的问题很少:
DockerfileDockerfileof-watchdogof-watchdogof-watchdog
所以,让我们解决这些问题!
注意:现在是提一下的好时机,OpenFaaS 社区已经在这些模板上做了很多工作。经典模板是旧模板,您应该使用中间件或它的 http 版本,并可能应用下面介绍的调整和更改。
openfaas-incubator/golang-http-templategolang-http
Dockerfile
FROM openfaas/of-watchdog:0.7.2 as watchdog
FROM golang:1.13.1-alpine3.10 as build
ARG GO111MODULE="on"
ENV CGO_ENABLED=0
RUN apk --no-cache add git
COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
RUN chmod +x /usr/bin/fwatchdog
WORKDIR /go/src/handler
COPY . .
# Run go test, gofmt, go vet
RUN chmod +x test.sh \
&& ./test.sh \
&& go build --ldflags "-s -w" -a -installsuffix cgo -o handler .
# Final runner image
FROM alpine:3.10
# Add non root user and certs
RUN apk --no-cache add ca-certificates \
&& addgroup -S app && adduser -S -g app app \
&& mkdir -p /home/app \
&& chown app /home/app
WORKDIR /home/app
COPY --from=build /go/src/handler/handler /usr/bin/fwatchdog /go/src/handler/function/ ./
RUN chown -R app /home/app
USER app
ENV fprocess="./handler" mode="http" upstream_url="http://127.0.0.1:8082"
CMD ["./fwatchdog"]
Dockerfile
FROMwatchdoggitwatchdog/go/src/handlertest.sh
# Collect test targets
SRC_DIRS="function"
TARGETS=$(for d in "$SRC_DIRS"; do echo ./$d/...; done)
# Run tests
echo "Running tests:"
go test -installsuffix "static" ${TARGETS} 2>&1
echo
# Collect all `.go` files and run `gofmt` against them. If some need formatting - print them.
echo -n "Checking gofmt: "
ERRS=$(find "$SRC_DIRS" -type f -name \*.go | xargs gofmt -l 2>&1 || true)
if [ -n "${ERRS}" ]; then
echo "FAIL - the following files need to be gofmt'ed:"
for e in ${ERRS}; do
echo " $e"
done
echo
exit 1
fi
echo "PASS"
echo
# Run `go vet` against all targets. If problems are found - print them.
echo -n "Checking go vet: "
ERRS=$(go vet ${TARGETS} 2>&1 || true)
if [ -n "${ERRS}" ]; then
echo "FAIL"
echo "${ERRS}"
echo
exit 1
fi
echo "PASS"
echo
test.sh
functiongo testgofmtgo vetDockerfilehandler
DockerfileRUNCOPYADDRUNappCOPYwatchdogwatchdog
Dockerfilemain.gohandler.go
测试时间
如果您阅读了我之前的任何帖子,您已经知道接下来会发生什么 - 单元测试。模板可以包含任何代码——包括测试,所以我认为添加简单的测试模板来为测试你的功能提供一些起点是合适的。所以,这里是示例测试:
package function
import (
"github.com/openfaas-incubator/go-function-sdk"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestHandleReturnsCorrectResponse(t *testing.T) {
expected := handler.Response{Body: []byte("Hello world, input was: John"), StatusCode: http.StatusOK}
response, err := Handle(handler.Request{Body: []byte("John"), Method: "GET"})
assert.Nil(t, err)
assert.Equal(t, response.StatusCode, expected.StatusCode)
assert.Equal(t, response.Body, expected.Body)
}
handler.gohandler_test.gohandler.ResponseHandle
将这一切结合在一起
template.yml
language: golang-mod
fprocess: ./handler
welcome_message: |
You created Golang function, that uses Go modules.
It includes simple handler as well as example unit test.
fprocessbuild_optionspackages
main.gogo.mod
module handler
go 1.12
replace handler/function => ./function
go mod tidyopenfaas-incubator/go-function-sdkstretchr/testify
现在剩下要做的就是构建、推送和部署它:
.../golang-mod $ docker build -t martinheinz/golang-mod .
...
Running tests:
ok handler/function 0.002s <- Out test passed!
Checking gofmt: PASS
Checking go vet: PASS
...
Successfully built 26847942c5c4
Successfully tagged martinheinz/golang-mod:latest
.../golang-mod $ docker push martinheinz/golang-mod:latest
.../golang-mod $ faas-cli deploy --image=martinheinz/golang-mod:latest --name=golang-mod-test
.../golang-mod $ echo "It's Working!" | faas-cli invoke golang-mod-test
Hello world, input was: It's Working!
结论
就这样,我们创建了可用于构建和部署 OpenFaaS 功能的自定义模板。话虽如此,还有一些事情要做......在下一篇博客文章中,我们将构建个人模板存储,我们可以在其中放置所有自定义模板,然后添加模板的自动验证并将其包含在 CI/CD 管道中,最后,我们将使用 Taskfile 简化与构建和运行模板相关的所有任务,就像我们在上一篇文章中对函数所做的那样。对于源代码的先睹为快,请参阅此处的我的存储库如果您喜欢这些类型的帖子,请随时留下反馈或给存储库加注星标。 😉