Docker快速部署(go的web项目为例)

本文详细介绍了如何使用Go语言后端代码结合Docker在Linux服务器上部署,包括Docker的基本概念、下载与安装、编写Dockerfile、部署GoWeb应用,以及如何管理和监控容器。特别提到Windows用户可能需要安装WSL。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Docker的快速使用

  • 此文章将以go语言后端代码搭配docker容器在服务器(Linux)进行部署,只说需要用到的一些docker命令,同时会给出命令相关参数的讲解。windows相关docker操作相同。下文出现与nil相关的内容,是因为我的项目是以nil为名,可以替换成其他的。
  • 下面关于docker的使用都是以容器名为例,如果出现错误,可以尝试将容器名改为对应的id(创建时候的初始化命名除外)

参考文献:go项目部署:docker部署go项目&直接运行二进制文件部署(两种方式进行部署)-CSDN博客

如何使用Docker部署Go Web应用 | 李文周的博客 (liwenzhou.com)

Docker 容器使用 | 菜鸟教程 (runoob.com)

1.docker的相关介绍

有关docker相关概念性理论可参考:Docker 教程 | 菜鸟教程 (runoob.com)

下面将以一个形象的例子向你解释docker。

​ Docker是一种开源的容器化平台,允许开发者将应用程序及其依赖打包成一个独立的、可移植的容器。它提供了一种简单而高效的方式来构建、部署和运行应用程序,使应用程序能够在不同的环境中以相同的方式运行。

​ 现在让我们通过一个形象的例子来解释Docker的概念。

​ 想象一下你是一名蛋糕师傅,你有一份精心制作的蛋糕食谱。你希望将这个食谱分享给其他人,让他们也能制作出同样美味的蛋糕。传统的方式是将食谱打印出来并分发给其他人,但这样做可能存在一些问题。

​ 首先,每个人可能会有自己的厨房和材料,这意味着他们可能需要根据自己的环境和材料做一些调整才能成功制作蛋糕。其次,如果你更新了食谱,你需要重新分发更新后的版本给每个人。

​ 现在,假设你使用Docker来容器化你的蛋糕食谱。你将食谱中所需的每个成分和步骤都清楚地列出来,并将其放入一个标记为"蛋糕容器"的容器中。这个容器包含了制作蛋糕所需的一切:配方、材料和步骤。

​ 现在,你可以将这个蛋糕容器分享给其他人,他们只需要在自己的厨房中运行这个容器,就可以按照你的精确配方制作出同样美味的蛋糕。无论他们使用的是Windows、Mac还是Linux,无论他们的厨房设置如何,这个蛋糕容器都能够在不同的环境中以一致的方式运行。

​ 如果你更新了蛋糕的配方,你只需要更新蛋糕容器中的食谱,然后通知其他人更新他们本地的容器即可。每个人都可以轻松地获取最新的食谱,并以相同的方式制作蛋糕。

这个例子中的"蛋糕容器"就好比是Docker容器,而食谱和制作蛋糕的过程就好比是应用程序和其依赖。通过使用Docker,开发者可以将应用程序及其依赖打包成一个独立的容器,使其能够在不同的环境中以一致的方式运行,从而简化了应用程序的开发、部署和管理过程。

2.docker的下载与安装

Ubuntu Docker:Ubuntu Docker 安装 | 菜鸟教程 (runoob.com)

Windows Docker:Windows Docker 安装 | 菜鸟教程 (runoob.com)

Linux云服务器:云服务器 | 菜鸟教程 (runoob.com)

ps:在windows下的docker desktop可能刚下载会有一个报错,是提醒你需要下载WSL,点击按钮进行相关下载即可。

3.利用docker进行go项目的部署

3.1在服务器上进行前期准备

​ ①提前编写好Docerfile文件(文件没有后缀名/拓展名),Dockerfile内容如下:

FROM golang:alpine AS builder

# 为我们的镜像设置必要的环境变量
ENV GO111MODULE=on \
    GOPROXY=https://goproxy.cn,direct \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64

# 移动到工作目录:/build
WORKDIR /build

# 将代码复制到容器中
COPY go.mod .
COPY go.sum .
# 下载依赖信息
RUN go mod download

#将代码复制到容器中
COPY . .



# 将我们的代码编译成二进制可执行文件 bubble
RUN go build -o nil_app .

###################
# 接下来创建一个小镜像
###################
FROM debian:bullseye-slim

# 从builder镜像中把静态文件拷贝到当前目录
COPY ./wait-for.sh /
#COPY ./templates /templates
#COPY ./static /static

# 从builder镜像中把配置文件拷贝到当前目录
COPY ./conf /conf

# 从builder镜像中把/dist/app 拷贝到当前目录
COPY --from=builder /build/nil_app /

RUN set -eux; \
	apt update; \
	apt install -y \
		--no-install-recommends \
		netcat; \
        chmod 755 wait-for.sh

#声明服务端口
EXPOSE 8888

# 需要运行的命令
ENTRYPOINT ["/nil_app"]

在上面的内容里,涉及到一个名为wait-for.sh的文件,文件内容如下:

#!/bin/bash

TIMEOUT=15
QUIET=0

ADDRS=()

echoerr() {
  if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}

usage() {
  exitcode="$1"
  cat << USAGE >&2
client:
  $cmdname host:port [host:port] [host:port] [-t timeout] [-- command args]
  -q | --quiet                        Do not output any status messages
  -t TIMEOUT | --timeout=timeout      Timeout in seconds, zero for no timeout
  -- COMMAND ARGS                     Execute command with args after the test finishes
USAGE
  exit "$exitcode"
}

wait_for() {
  results=()
  for addr in ${ADDRS[@]}
  do
    HOST=$(printf "%s\n" "$addr"| cut -d : -f 1)
    PORT=$(printf "%s\n" "$addr"| cut -d : -f 2)
    result=1
    for i in `seq $TIMEOUT` ; do
      nc -z "$HOST" "$PORT" > /dev/null 2>&1
      result=$?
      if [ $result -ne 0 ] ; then
        sleep 1
	continue
      fi
      break
    done
    results=(${results[@]} $result)
  done
  num=${#results[@]}
  for result in ${results[@]}
  do
    if [ $result -eq 0 ] ; then
	    num=`expr $num - 1`
    fi
  done
  if [ $num -eq 0 ] ; then
    if [ $# -gt 0 ] ; then
      exec "$@"
    fi
    exit 0
  fi
  echo "Operation timed out" >&2
  exit 1
}

while [ $# -gt 0 ]
do
  case "$1" in
    *:* )
    ADDRS=(${ADDRS[@]} $1)
    shift 1
    ;;
    -q | --quiet)
    QUIET=1
    shift 1
    ;;
    -t)
    TIMEOUT="$2"
    if [ "$TIMEOUT" = "" ]; then break; fi
    shift 2
    ;;
    --timeout=*)
    TIMEOUT="${1#*=}"
    shift 1
    ;;
    --)
    shift
    break
    ;;
    --help)
    usage 0
    ;;
    *)
    echoerr "Unknown argument: $1"
    usage 1
    ;;
  esac
done

if [ "${#ADDRS[@]}" -eq 0 ]; then
  echoerr "Error: you need to provide a host and port to test."
  usage 2
fi

wait_for "$@"

​ ②修改配置文件,将host进行修改,后续会在 3.3其他 中解释为什么需要修改。

image-20240428132642763

​ ③将项目文件全部copy到服务器上面,如下: image-20240428132839576

3.2相关docker部署操作

3.2.1 确保docker可以正常使用(windows下打开docker desktop,显示正常页面即可)

​ 经典hello world!!!

docker run ubuntu:15.10 /bin/echo "Hello world"

显示下图表示docker创建一个容器并成功运行

image-20240428133622190

参数解析:

  • docker: Docker 的二进制执行文件。
  • run: 与前面的 docker 组合来运行一个容器。
  • ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
  • /bin/echo “Hello world”: 在启动的容器里执行的命令

3.2.2 进行go的web项目部署:

(1)拉取/构建 镜像(这点的镜像就相当于上面做蛋糕例子里面的材料,准备材料):

​ 我们的项目用到了mysql,redis,以及go相关内容

拉取mysql,redis的镜像(参考文献:Docker 安装 MySQL | 菜鸟教程 (runoob.com))

docker pull mysql:latest

image-20240428134229333

docker pull redis:latest

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

参数解析:

  • docker pull:组合到一起表示拉去镜像
  • **mysql:latest中的mysql:**表示需要拉取的镜像是mysql数据库的镜像
  • mysql:latest中的latest: 表示版本,此处latest代表最新版本,后续有新版本需要重新拉取

​ 有关镜像版本问题可以取参考文献中查找

例如利用: docker search mysql 就可以查看mysql各个版本

对go项目进行构建镜像

docker build . -t nil_image

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

参数解析:

  • docker build:表示构建镜像,需要一个Dockerfile文件进行指引(上文我们已经创建好的)
  • -t :指定要创建的目标镜像名
  • nil_image: 表示镜像名

(2)查看镜像是否正常 拉取/构建 成功

docker images

image-20240428135720006

(3)创建容器(蛋糕材料已准备好,放进盒子里打包起来)

mysql容器创建:

$ docker run -itd --name nil_mysql -p 13306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

参数解析:

  • -p 13306:3306 :映射容器服务的 3306 端口到宿主机(服务器本机)的 13306 端口,外部主机可以直接 通过 宿主机ip:13306 访问到 MySQL 的服务。
  • MYSQL_ROOT_PASSWORD=123456:设置 MySQL 服务 root 用户的密码。
  • **-itd:**在后台运行,不显示到前台
  • **–name:**指定要创建的目标容器名
  • nil_mysql:指定的容器名
  • **mysql:**需要使用到的镜像名

ps:此处映射到13306可以防止端口冲突,如果13306发生冲突的话,可以使用其他的本机空闲端口。

进入msyql容器中,进行相关数据库和表的创建:

docker exec -it mysql /bin/bash

image-20240428142918293

image-20240428142938512

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

redis容器创建:

$ docker run -itd --name nil_redis -p 6379:6379 redis

可以使用下面命令进入redis容器里进行相关操作

docker exec -it mysql /bin/bash

go项目的容器启动

docker run -itd --name nil --link=nil_mysql:nil_mysql --link=nil_redis:nil_redis -p 8888:8888 nil_image

image-20240428143150012

参数解析:

  • **–link=nil_mysql:nil_mysql:**link表示与其他容器进行连接。在go项目中,我们将host改为nil_mysql,
    前面一个nil_mysql表示的是go里面conf文件下mysql的host配置,后面一个是nil_mysql容器,将二者进行连接。
  • **–link=nil_redis:nil_redis:**与mysql相同
  • **-p 8888:8888:**前一个8888表示映射到本机(服务器本机)的8888端口,外部就可以访问该服务器的8888端口进行web服务。后一个是容器中的8888端口,后一个的8888端口要与web框架连接的端口号一致。

经过上述步骤:就已经完成了goweb项目的服务器部署,外部就可以访问我们的api接口了!

3.3 其他

①:每一个容器都可以看成一个小电脑,里面也有众多端口号。上文的-p简单的可以看成一个远程连接。如

​ -p 8080:8888 就可以理解为,本机的8080端口对接容器中的8888端口,当外部访问本机的8080端口时,就跳转到容器中的8888端口进行相关服务。

②:

如何查看容器(项目)是否正常运行

docker ps -a

image-20240428150349816

  • **-a: **此处-a表示显示全部(all)的容器,包括已停用的。如果没有这个参数,只显示运行中的。

容器的运行情况(ctrl+c可以强行终止查看)

docker stats -a

image-20240428144530300

**-a: **此处-a表示显示全部(all)的容器运行情况,包括已停用的。如果没有这个参数,只显示运行中的。

容器的暂停,启动与删除

docker stop nil
docker start nil

image-20240428144748611

docker rm nil

③:如何像控制台一样查看他们的运行情况

windows下,打开docker desktop,找到view detail即可

image-20240428144912803

image-20240428144920532

linux下:

docker logs --tail 10 nil

image-20240428145135098

参数解析:

  • **docker logs: **显示日志(detail)
  • **–tail 10: **显示最新(tail-末尾)的十条,不使用这个参数,就展示所有的记录
  • **nil:**要查看的容器名

④:go项目conf配置文件的相关解释

图中host表示要连接的容器的名字,端口表示的是容器里面对应服务的端口号。

如上文中的nil_mysql容器(看作一个小电脑),他里面的mysql服务是在容器的3306端口下。

所以配置文件里任然是3306,而不是nil_mysql容器映射到本机的13306端口。

如果填写的是13306,那么访问的是容器里面的13306端口,是没有服务的。

image-20240428132642763

后续可能会出如何利用docker-compose去解决容器连接的问题。

谢谢大家了!ヾ(≧▽≦)o*

有问题或者建议可以私信我

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值