介绍 (Introduction)
Docker is the most common containerization software used today. It enables developers to easily package apps along with their environments, which allows for quicker iteration cycles and better resource efficiency, while providing the same desired environment on each run. Docker Compose is a container orchestration tool that facilitates modern app requirements. It allows you to run multiple interconnected containers at the same time. Instead of manually running containers, orchestration tools give developers the ability to control, scale, and extend a container simultaneously.
Docker是当今使用的最常见的容器化软件。 它使开发人员可以轻松地将应用程序与其环境打包在一起,从而加快迭代周期并提高资源效率,同时在每次运行时提供相同的所需环境。 Docker Compose是一个容器编排工具,可满足现代应用程序的需求。 它允许您同时运行多个互连的容器。 编排工具代替了手动运行容器,而使开发人员能够同时控制,缩放和扩展容器。
The benefits of using Nginx as a front-end web server are its performance, configurability, and TLS termination, which frees the app from completing these tasks. The nginx-proxy
is an automated system for Docker containers that greatly simplifies the process of configuring Nginx to serve as a reverse proxy. Its Let’s Encrypt add-on can accompany the nginx-proxy
to automate the generation and renewal of certificates for proxied containers.
将Nginx用作前端Web服务器的好处是其性能,可配置性和TLS终止,这使该应用程序摆脱了完成这些任务的负担。 nginx-proxy
是一个用于Docker容器的自动化系统,大大简化了将Nginx配置为充当反向代理的过程。 它的“ 让我们加密” 附加组件可以与nginx-proxy
以自动生成和更新代理容器的证书。
In this tutorial, you will deploy an example Go web application with gorilla/mux as the request router and Nginx as the web server, all inside Docker containers, orchestrated by Docker Compose. You’ll use nginx-proxy
with the Let’s Encrypt add-on as the reverse proxy. At the end of this tutorial, you will have deployed a Go web app accessible at your domain with multiple routes, using Docker and secured with Let’s Encrypt certificates.
在本教程中,您将部署一个示例Go Web应用程序,该应用程序将gorilla / mux作为请求路由器,将Nginx作为Web服务器,它们都在Docker容器内,由Docker Compose精心组织。 您将使用带有Let's Encrypt插件的nginx-proxy
作为反向代理。 在本教程的最后,您将部署一个Go Web应用程序,该应用程序可以使用Docker在您的域中通过多个路由进行访问,并使用Let's Encrypt证书进行保护。
先决条件 (Prerequisites)
An Ubuntu 18.04 server with root privileges, and a secondary, non-root account. You can set this up by following this initial server setup guide. For this tutorial the non-root user is
sammy
.具有root用户特权的Ubuntu 18.04服务器和一个非root用户辅助帐户。 您可以按照本初始服务器安装指南进行设置 。 在本教程中,非root用户是
sammy
。Docker installed by following the first two steps of How To Install Docker on Ubuntu 18.04.
通过遵循如何在Ubuntu 18.04上安装Docker的前两个步骤来安装Docker 。
Docker Compose installed by following the first step of How To Install Docker Compose on Ubuntu 18.04. You only need to do the first step.
遵循如何在Ubuntu 18.04上安装Docker Compose的第一步来安装Docker Compose 。 您只需要执行第一步。
A fully registered domain name. This tutorial will use
example.com
throughout. You can get one for free on Freenom, or use the domain registrar of your choice.完全注册的域名。 本教程将始终使用
example.com
。 您可以在Freenom上免费获得一个,或使用您选择的域名注册商。A DNS “A” record with
example.com
pointing to your server’s public IP address. You can follow this introduction to DigitalOcean DNS for details on how to add them.带有
example.com
DNS“ A”记录指向您服务器的公共IP地址。 您可以按照DigitalOcean DNS 简介进行操作,以获取有关如何添加它们的详细信息。An understanding of Docker and its architecture. For an introduction to Docker, see The Docker Ecosystem: An Introduction to Common Components.
了解Docker及其架构。 有关Docker的介绍,请参阅Docker生态系统:通用组件介绍 。
第1步-创建示例Go Web App (Step 1 — Creating an Example Go Web App)
In this step, you will set up your workspace and create a simple Go web app, which you’ll later containerize. The Go app will use the powerful gorilla/mux request router, chosen for its flexibility and speed.
在此步骤中,您将设置工作区并创建一个简单的Go Web应用程序,稍后将其容器化。 Go应用将使用强大的大猩猩/多路复用器请求路由器,该路由器因其灵活性和速度而选择。
Start off by logging in as sammy
:
首先以sammy
登录:
ssh sammy@your_server_ip
ssh sammy @ your_server_ip
For this tutorial, you’ll store all data under ~/go-docker
. Run the following command to do this:
对于本教程,您将所有数据存储在~/go-docker
。 运行以下命令以执行此操作:
- mkdir ~/go-docker mkdir〜/ go-docker
Navigate to it:
导航到它:
- cd ~/go-docker cd〜/ go-docker
You’ll store your example Go web app in a file named main.go
. Create it using your text editor:
您会将示例Go Web应用程序存储在名为main.go
的文件中。 使用您的文本编辑器创建它:
- nano main.go 纳米main.go
Add the following lines:
添加以下行:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>This is the homepage. Try /hello and /hello/Sammy\n</h1>")
})
r.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Hello from Docker!\n</h1>")
})
r.HandleFunc("/hello/{name}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
title := vars["name"]
fmt.Fprintf(w, "<h1>Hello, %s!\n</h1>", title)
})
http.ListenAndServe(":80", r)
}
You first import net/http
and gorilla/mux
packages, which provide HTTP server functionality and routing.
首先导入net/http
和gorilla/mux
软件包,它们提供HTTP服务器功能和路由。
The gorilla/mux
package implements an easier and more powerful request router and dispatcher, while at the same time maintaining interface compatibility with the standard router. Here, you instantiate a new mux
router and store it in variable r
. Then, you define three routes: /
, /hello
, and /hello/{name}
. The first (/
) serves as the homepage and you include a message for the page. The second (/hello
) returns a greeting to the visitor. For the third route (/hello/{name}
) you specify that it should take a name as a parameter and show a greeting message with the name inserted.
gorilla/mux
软件包实现了更轻松,功能更强大的请求路由器和调度程序,同时又保持了与标准路由器的接口兼容性。 在这里,您实例化了一个新的mux
路由器,并将其存储在变量r
。 然后,定义三个路由: /
, /hello
和/hello/{name}
。 第一个( /
)用作主页,并且包含该页面的消息。 第二个( /hello
)向访问者返回问候语。 对于第三条路由( /hello/{name}
),您指定它应使用名称作为参数并显示带有该名称的问候消息。
At the end of your file, you start the HTTP server with http.ListenAndServe
and instruct it to listen on port 80
, using the router you configured.
在文件末尾,使用http.ListenAndServe
启动HTTP服务器,并指示它使用您配置的路由器在端口80
上进行侦听。
Save and close the file.
保存并关闭文件。
Before running your Go app, you first need to compile and pack it for execution inside a Docker container. Go is a compiled language, so before a program can run, the compiler translates the programming code into executable machine code.
在运行Go应用之前,您首先需要对其进行编译和打包以在Docker容器中执行。 Go是一种编译语言 ,因此在程序运行之前,编译器会将编程代码转换为可执行的机器代码。
You’ve set up your workspace and created an example Go web app. Next, you will deploy nginx-proxy
with an automated Let’s Encrypt certificate provision.
您已经设置了工作区并创建了一个示例Go Web应用程序。 接下来,您将使用自动的“我们加密”证书配置来部署nginx-proxy
。
第2步-使用“让我们加密”部署nginx-proxy (Step 2 — Deploying nginx-proxy with Let’s Encrypt)
It’s important that you secure your app with HTTPS. To accomplish this, you’ll deploy nginx-proxy
via Docker Compose, along with its Let’s Encrypt add-on. This secures Docker containers proxied using nginx-proxy
, and takes care of securing your app through HTTPS by automatically handling TLS certificate creation and renewal.
使用HTTPS保护应用程序很重要。 为此,您将通过Docker Compose以及其Let's Encrypt 插件部署nginx-proxy
。 这样可以保护使用nginx-proxy
Docker容器,并通过自动处理TLS证书的创建和更新来确保通过HTTPS保护应用程序的安全。
You’ll be storing the Docker Compose configuration for nginx-proxy
in a file named nginx-proxy-compose.yaml
. Create it by running:
您将在一个名为nginx-proxy-compose.yaml
的文件中存储nginx-proxy
的Docker Compose配置。 通过运行以下命令创建它:
nano nginx-proxy-compose.yaml
纳米nginx-proxy-compose.yaml
Add the following lines to the file:
将以下行添加到文件中:
version: '2'
services:
nginx-proxy:
restart: always
image: jwilder/nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- "/etc/nginx/vhost.d"
- "/usr/share/nginx/html"
- "/var/run/docker.sock:/tmp/docker.sock:ro"
- "/etc/nginx/certs"
letsencrypt-nginx-proxy-companion:
restart: always
image: jrcs/letsencrypt-nginx-proxy-companion
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
volumes_from:
- "nginx-proxy"
Here you’re defining two containers: one for nginx-proxy
and one for its Let’s Encrypt add-on (letsencrypt-nginx-proxy-companion
). For the proxy, you specify the image jwilder/nginx-proxy
, expose and map HTTP and HTTPS ports, and finally define volumes that will be accessible to the container for persisting Nginx-related data.
在这里,您将定义两个容器:一个用于nginx-proxy
,一个用于其Let's Encrypt附加组件( letsencrypt-nginx-proxy-companion
)。 对于代理,您可以指定映像jwilder/nginx-proxy
,公开并映射HTTP和HTTPS端口,最后定义容器可访问的卷,以保留与Nginx相关的数据。
In the second block, you name the image for the Let’s Encrypt add-on configuration. Then, you configure access to Docker’s socket by defining a volume and then the existing volumes from the proxy container to inherit. Both containers have the restart
property set to always
, which instructs Docker to always keep them up (in the case of a crash or a system reboot).
在第二个块中,将图像命名为“让我们加密”附加组件配置。 然后,通过定义一个卷,然后定义要从代理容器继承的现有卷,来配置对Docker套接字的访问。 两个容器的restart
属性都设置为always
,指示Docker始终保持它们(在崩溃或系统重启的情况下)。
Save and close the file.
保存并关闭文件。
Deploy the nginx-proxy
by running:
通过运行以下命令部署nginx-proxy
:
docker-compose -f nginx-proxy-compose.yaml up -d
docker -compose -f nginx-proxy-compose.yaml up -d
Docker Compose accepts a custom named file via the -f
flag. The up
command runs the containers, and the -d
flag, detached mode, instructs it to run the containers in the background.
Docker Compose通过-f
标志接受自定义的命名文件。 up
命令运行容器,分离模式下的-d
标志指示其在后台运行容器。
Your final output will look like this:
您的最终输出将如下所示:
Output
Creating network "go-docker_default" with the default driver
Pulling nginx-proxy (jwilder/nginx-proxy:)...
latest: Pulling from jwilder/nginx-proxy
a5a6f2f73cd8: Pull complete
2343eb083a4e: Pull complete
...
Digest: sha256:619f390f49c62ece1f21dfa162fa5748e6ada15742e034fb86127e6f443b40bd
Status: Downloaded newer image for jwilder/nginx-proxy:latest
Pulling letsencrypt-nginx-proxy-companion (jrcs/letsencrypt-nginx-proxy-companion:)...
latest: Pulling from jrcs/letsencrypt-nginx-proxy-companion
...
Creating go-docker_nginx-proxy_1 ... done
Creating go-docker_letsencrypt-nginx-proxy-companion_1 ... done
You’ve deployed nginx-proxy
and its Let’s Encrypt companion using Docker Compose. Next, you’ll create a Dockerfile for your Go web app.
您已经使用Docker Compose部署了nginx-proxy
及其“让我们加密”伴侣。 接下来,您将为Go Web应用程序创建一个Dockerfile。
第3步-对Go Web App进行Docker化 (Step 3 — Dockerizing the Go Web App)
In this section, you will create a Dockerfile containing instructions on how Docker will create an immutable image for your Go web app. Docker builds an immutable app image—similar to a snapshot of the container—using the instructions found in the Dockerfile. The image’s immutability guarantees the same environment each time a container, based on the particular image, is run.
在本部分中,您将创建一个Dockerfile,其中包含有关Docker如何为Go Web应用程序创建不可变映像的说明。 Docker使用Dockerfile中的指令构建不可变的应用程序映像(类似于容器的快照)。 图像的不变性确保每次运行基于特定图像的容器时都具有相同的环境。
Create the Dockerfile
with your text editor:
使用文本编辑器创建Dockerfile
:
- nano Dockerfile 纳米Dockerfile
Add the following lines:
添加以下行:
FROM golang:alpine AS build
RUN apk --no-cache add gcc g++ make git
WORKDIR /go/src/app
COPY . .
RUN go get ./...
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/web-app ./main.go
FROM alpine:3.9
RUN apk --no-cache add ca-certificates
WORKDIR /usr/bin
COPY --from=build /go/src/app/bin /go/bin
EXPOSE 80
ENTRYPOINT /go/bin/web-app --port 80
This Dockerfile has two stages. The first stage uses the golang:alpine
base, which contains pre-installed Go on Alpine Linux.
该Dockerfile有两个阶段。 第一阶段使用golang:alpine
基础,其中包含在Alpine Linux上预安装的Go。
Then you install gcc
, g++
, make
, and git
as the necessary compilation tools for your Go app. You set the working directory to /go/src/app
, which is under the default GOPATH. You also copy the content of the current directory into the container. The first stage concludes with recursively fetching the packages used from the code and compiling the main.go
file for release without symbol and debug info (by passing -ldflags="-s -w"
). When you compile a Go program it keeps a separate part of the binary that would be used for debugging, however, this extra information uses memory, and is not necessary to preserve when deploying to a production environment.
然后,安装gcc
, g++
, make
和git
作为Go应用程序的必要编译工具。 您将工作目录设置为/go/src/app
,该目录位于默认的GOPATH下 。 您还将当前目录的内容复制到容器中。 第一阶段的结论是递归地从代码中获取使用的软件包,并编译main.go
文件以在不包含符号和调试信息的情况下进行发布(通过传递-ldflags="-s -w"
)。 当您编译Go程序时,它将保留二进制文件的单独部分,该二进制文件将用于调试,但是,这些额外的信息会占用内存,并且在部署到生产环境时不必保留。
The second stage bases itself on alpine:3.9
(Alpine Linux 3.9). It installs trusted CA certificates, copies the compiled app binaries from the first stage to the current image, exposes port 80
, and sets the app binary as the image entry point.
第二阶段基于alpine:3.9
(Alpine Linux 3.9)。 它安装受信任的CA证书,将编译后的应用程序二进制文件从第一阶段复制到当前映像,公开端口80
,然后将应用程序二进制文件设置为映像入口点。
Save and close the file.
保存并关闭文件。
You’ve created a Dockerfile for your Go app that will fetch its packages, compile it for release, and run it upon container creation. In the next step, you will create the Docker Compose yaml
file and test the app by running it in Docker.
您已经为Go应用程序创建了一个Dockerfile,它将获取其程序包,对其进行编译以进行发布,并在创建容器时运行它。 在下一步中,您将创建Docker Compose yaml
文件,并通过在Docker中运行它来测试应用程序。
步骤4 —创建和运行Docker Compose文件 (Step 4 — Creating and Running the Docker Compose File)
Now, you’ll create the Docker Compose config file and write the necessary configuration for running the Docker image you created in the previous step. Then, you will run it and check if it works correctly. In general, the Docker Compose config file specifies the containers, their settings, networks, and volumes that the app requires. You can also specify that these elements can start and stop as one at the same time.
现在,您将创建Docker Compose配置文件,并编写必要的配置以运行在上一步中创建的Docker映像。 然后,您将运行它并检查它是否正确运行。 通常,Docker Compose配置文件指定应用程序所需的容器,其设置,网络和卷。 您还可以指定这些元素可以同时作为一个开始和停止。
You will be storing the Docker Compose configuration for the Go web app in a file named go-app-compose.yaml
. Create it by running:
您将把Go Web应用程序的Docker Compose配置存储在名为go-app-compose.yaml
的文件中。 通过运行以下命令创建它:
nano go-app-compose.yaml
纳米go-app-compose.yaml
Add the following lines to this file:
将以下行添加到此文件:
version: '2'
services:
go-web-app:
restart: always
build:
dockerfile: Dockerfile
context: .
environment:
- VIRTUAL_HOST=example.com
- LETSENCRYPT_HOST=example.com
Remember to replace example.com
both times with your domain name. Save and close the file.
请记住两次都用您的域名替换example.com
。 保存并关闭文件。
This Docker Compose configuration contains one container (go-web-app
), which will be your Go web app. It builds the app using the Dockerfile you’ve created in the previous step, and takes the current directory, which contains the source code, as the context for building. Furthermore, it sets two environment variables: VIRTUAL_HOST
and LETSENCRYPT_HOST
. nginx-proxy
uses VIRTUAL_HOST
to know from which domain to accept the requests. LETSENCRYPT_HOST
specifies the domain name for generating TLS certificates, and must be the same as VIRTUAL_HOST
, unless you specify a wildcard domain.
此Docker Compose配置包含一个容器( go-web-app
),它将成为您的Go Web应用程序。 它使用您在上一步中创建的Dockerfile来构建应用程序,并使用包含源代码的当前目录作为构建上下文。 此外,它设置了两个环境变量: VIRTUAL_HOST
和LETSENCRYPT_HOST
。 nginx-proxy
使用VIRTUAL_HOST
知道从哪个域接受请求。 LETSENCRYPT_HOST
指定用于生成TLS证书的域名,并且必须与VIRTUAL_HOST
相同,除非您指定通配符域。
Now, you’ll run your Go web app in the background via Docker Compose with the following command:
现在,您将使用以下命令通过Docker Compose在后台运行Go Web应用程序:
- docker-compose -f go-app-compose.yaml up -d docker-compose -f go-app-compose.yaml up -d
Your final output will look like the following:
您的最终输出将如下所示:
Output
Creating network "go-docker_default" with the default driver
Building go-web-app
Step 1/12 : FROM golang:alpine AS build
---> b97a72b8e97d
...
Successfully tagged go-docker_go-web-app:latest
WARNING: Image for service go-web-app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating go-docker_go-web-app_1 ... done
If you review the output presented after running the command, Docker logged every step of building the app image according to the configuration in your Dockerfile.
如果您查看运行命令后显示的输出,则Docker会根据Dockerfile中的配置记录构建应用程序映像的每个步骤。
You can now navigate to https://example.com/
to see your homepage. At your web app’s home address, you’re seeing the page as a result of the /
route you defined in the first step.
您现在可以导航到https:// example.com /
来查看您的主页。 在Web应用程序的家庭地址中,您会看到由于第一步中定义的/
路由而导致的页面。
Now navigate to https://example.com/hello
. You will see the message you defined in your code for the /hello
route from Step 1.
现在导航到https:// example.com /hello
。 您将看到在代码中为步骤1中的/hello
路由定义的消息。
Finally, try appending a name to your web app’s address to test the other route, like: https://example.com/hello/Sammy
.
最后,尝试将名称附加到您的Web应用程序的地址以测试其他路由,例如: https:// example.com /hello/Sammy
。
Note: In the case that you receive an error about invalid TLS certificates, wait a few minutes for the Let’s Encrypt add-on to provision the certificates. If you are still getting errors after a short time, double check what you’ve entered against the commands and configuration shown in this step.
注意:如果您收到有关无效TLS证书的错误消息,请等待几分钟,让“加密”加载项提供证书。 如果短时间后仍然出现错误,请对照此步骤中显示的命令和配置仔细检查输入的内容。
You’ve created the Docker Compose file and written configuration for running your Go app inside a container. To finish, you navigated to your domain to check that the gorilla/mux
router setup is serving requests to your Dockerized Go web app correctly.
您已经创建了Docker Compose文件并编写了配置,以在容器中运行Go应用。 最后,您导航到您的域以检查gorilla/mux
路由器设置是否正确地向Dockerized Go网络应用提供了请求。
结论 (Conclusion)
You have now successfully deployed your Go web app with Docker and Nginx on Ubuntu 18.04. With Docker, maintaining applications becomes less of a hassle, because the environment the app is executed in is guaranteed to be the same each time it’s run. The gorilla/mux package has excellent documentation and offers more sophisticated features, such as naming routes and serving static files. For more control over the Go HTTP server module, such as defining custom timeouts, visit the official docs.
现在,您已在Ubuntu 18.04上成功使用Docker和Nginx部署了Go Web应用程序。 使用Docker,维护应用程序变得不再那么麻烦,因为保证了应用程序每次运行时所处的环境都是相同的。 gorilla / mux软件包提供了出色的文档,并提供了更复杂的功能,例如命名路由和提供静态文件。 要对Go HTTP服务器模块进行更多控制,例如定义自定义超时,请访问官方文档 。