Docker部署Gin项目初体验

这是我第一次接触和使用Gin框架和MySQL数据库,也算是第一次尝试

项目名为SayHello,模仿李辉大佬的Flask书籍中的第一个实战项目,不用Flask是因为正在入门Gin

项目的功能是一个留言板,但我做的是一个阉割版(因为最近上网课作业是真多,唉,写不完〒▽〒,时间又太少了,又想尝试一下完整的过程)

目录

1、前端设计

2、后端实现

3、编写Dockerfile文件

4、部署到阿里云服务器


项目目录:

SayHello

|

步骤如下:

1、前端设计

前端内容比较简单,代码及效果如下

/static/SayHello.css

html{
    background-color: aliceblue;
}
body{
    background-color: aliceblue;
    width: 1000px;
    height: auto;
    margin: auto;

}
header{
    height: 100px;
    font-weight: bold;
    text-shadow: lightgray;
    vertical-align: middle;
    color: #ff7b23;
    font-size: 80px;
    text-align: center;
    line-height: 100px;
    margin: 20px auto;
    background-color: papayawhip;
    border-radius: 5px;
    box-shadow: 3px 3px 3px lightgrey;

}

.font{
    color: black;
    font-weight: bold;
    font-size: 20px;
    display: inline;
}
#main{
    background-color: papayawhip;
    height: auto;
    border-radius: 5px;
    box-shadow: 3px 3px 3px lightgray ;

}
#head{
    width: 1000px;
    height: 120px;
    margin: 0 auto;
}
#head-font{
    font-size: 30px;
    color: gray;
    font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
    font-weight: bold;
    text-align: center;
    margin-top: 30px;
    margin-bottom: 10px;

}

.c-checkbox {
    display: none;
}
.c-checkbox:checked + .c-formContainer .c-form {
    width: 30em;
}
.c-checkbox:checked + .c-formContainer .c-form__toggle {
    visibility: hidden;
    opacity: 0;
    transform: scale(0.7);
}
.c-checkbox:checked + .c-formContainer .c-form__input,
.c-checkbox:checked + .c-formContainer .c-form__buttonLabel {
    transition: 0.2s 0.1s;
    visibility: visible;
    opacity: 1;
    transform: scale(1);
}
.c-checkbox:not(:checked) + .c-formContainer .c-form__input:required:valid ~ .c-form__toggle::before, .c-checkbox:checked + .c-formContainer .c-form__input:required:valid ~ .c-form__toggle::before {
    content: 'Thank You! \1F60A';
}
.c-checkbox:not(:checked) + .c-formContainer .c-form__input:required:valid ~ .c-form__toggle {
    pointer-events: none;
    cursor: default;
}

.c-formContainer,
.c-form,
.c-form__toggle {
    width: 10em;
    height: 4em;
}

.c-formContainer {
    font-weight: 700;
}

@keyframes light{
    0%{
        box-shadow: 0 5px 20px rgba(255, 63, 25, 0.5);
    }

    50%{
        box-shadow: 0 5px 20px rgba(255, 240, 200, 0.5);
    }

    100%{
        box-shadow: 0 5px 20px rgba(255, 63, 25, 0.5);
    }
}
.c-form__toggle {
    position: absolute;
    border-radius: 6.25em;
    background-color: #ffcccc;
    box-shadow: 0 5px 20px rgba(255, 63, 25, 0.5);
    transition: 0.2s;
}

.c-form__toggle:hover{
    position: absolute;
    border-radius: 6.25em;
    background-color: #ffcccc;
    box-shadow: 0 5px 20px rgba(255, 63, 25, 0.5);
    transition: 0.2s;
    animation: light 1s linear infinite;
}

.c-form{
    position: absolute;
    border-radius: 6.25em;
    background-color:#ffffff;
    transition: 0.2s;
}

.c-form {
    left: 50%;
    transform: translateX(-50%);
    padding: 0.625em;
    box-sizing: border-box;
    display: flex;
    justify-content: center;
}

.c-form__toggle {
    color: #ff7b73;
    top: 0;
    cursor: pointer;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}
.c-form__toggle::before {
    font-size: 1.25em;
    content: attr(data-title);
}

.c-form__input,
.c-form__button {
    font: inherit;
    border: 0;
    outline: 0;
    border-radius: 5em;
    box-sizing: border-box;
}

.c-form__input,
.c-form__buttonLabel {
    font-size: 1.2em;
    opacity: 0;
    visibility: hidden;
    transform: scale(0.7);
    transition: 0s;
}

.c-form__input {
    color: #ffcccc;

}
.c-form__input::placeholder {
    color: currentColor;
}
.c-form__input:required:valid {
    color: #ff7b73;
}
.c-form__input:required:valid + .c-form__buttonLabel {
    color: #ffffff;
}
.c-form__input:required:valid + .c-form__buttonLabel::before {
    pointer-events: initial;
}

.c-form__buttonLabel {
    color: #ffaea9;
    height: 100%;
    width: auto;
}
.c-form__buttonLabel::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    pointer-events: none;
    cursor: pointer;
}

.c-form__button {
    color: white;
    font-weight: bolder;
    line-height: 100%;
    padding: 0;
    height: 100%;
    width: 5em;
    background-color: #ff7b73;
}


#input{
    margin: 0 100px;
}
input{
    width: 16em;
    height: 100%;
    border-radius: 50%;
    text-align: center;
    margin: 0 2em;
}
hr{
    width: 800px;
    color: grey;
}
#content{
    margin: 0 100px;
}
li{
    display: inline-block;
    min-width: 500px;
    height: 50px;
    border: 1px solid lightgray;
    border-radius: 5px;
    list-style-type: none;
    line-height: 50px;
    margin: 5px auto;
}
.li-font{
    font-size: 25px;
    color: gray;

}
.button{
    width: 50px;
    height: 50px;
    border-radius: 50%;
}
.sure{
    background-color: lawngreen;
    font-size: 25px;
    text-align: center;
    line-height: 50px;
}
.cancel{
    background-color: #ff7b73;
    font-size: 25px;
    text-align: center;
    line-height: 50px;
}

/templates/SayHello.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta lang="zh-CN">
    <title>SayHello</title>
    <link rel="shortcut icon" type="image/x-icon" href="/static/SayHelloico.ico">
    <link rel="stylesheet" href="../static/SayHello.css">
    <script type="text/javascript">
        function Thank() {
            alert("Thank you!")
        }
        /**
         * @return {boolean}
         */
        function Delete(){
            return confirm("Are you Sure?");
        }
    </script>
</head>
<body>
<header>
    Say Hello <p class="font">to the World</p>
</header>
<div id="main">
    <div id="head">
        <p id="head-font">Tell The World What You Want To Say</p>

        <input class="c-checkbox" type="checkbox" id="checkbox">
        <div class="c-formContainer">
            <form class="c-form" action="/" method="post">
                <label>
                    <input name="content" class="c-form__input" placeholder="Say Hello" type="text" maxlength="20">
                </label>
                <label class="c-form__buttonLabel" for="checkbox">
                    <button class="c-form__button" type="button" >send</button>
                </label>

                <label class="c-form__toggle" for="checkbox" data-title="Notify me"></label>
            </form>
        </div>

    </div>
    <div id="content">
        <div>
            {{ range $i,$value:=.contents }}
                {{ if $value.WORD }}
                    <li class="li-font">{{ $value.WORD }}</li>
                    <form action="#" style="display: inline">
                        <button class="sure button" onclick="Thank()">√</button>
                    </form>
                    <form action="/del/{{$value.ID }}" method="post" style="display: inline">
                        <button class="cancel button" onclick="return Delete()">×</button>
                    </form>
                {{end}}
            {{ end }}
        </div>
    </div>
</div>
</body>
</html>

2、后端实现

在这里我还没有下载MySQL,所以直接使用Docker push了MySQL镜像

具体操作:

C:\Users\admin>docker push mysql
The push refers to repository [docker.io/library/mysql]
797622a2c5eb: Layer already exists                                                                                      750760613cac: Layer already exists                                                                                      46138c79bcf0: Layer already exists                                                                                      7d021d828f72: Layer already exists                                                                                      b0019e07d5a5: Layer already exists                                                                                      ace74cb61ec0: Layer already exists                                                                                      d84f8cf1dc23: Layer already exists                                                                                      24bd91e7be37: Layer already exists                                                                                      49baacc63c3b: Layer already exists                                                                                      8d3b3830445d: Layer already exists                                                                                      49003fe88142: Layer already exists                                                                                      c2adabaecedb: Layer already exists 

启动一个MySQL容器

//这是Windows操作系统,数据卷挂载时挂载到D:\DockerVolume\mysql\data目录,保证目录存在
//可以用docker logs mysql 查看mysql容器启动日志

docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=YourPassWord -v /d/DockerVolume/mysql/data:/var/lib/mysql mysql


//启动一个MySQL client进行交互 -u是user -p 是password
docker run -it --network host --rm mysql mysql -h127.0.0.1 -p3306 --default-character-set=utf8mb4 -uroot -p


//因为Gorm是无法帮你创建数据库的,所以需要手动创建数据库
CREATE DATABASE SayHello
use database SayHello;
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"strings"

	//导入驱动文件
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"net/http"
	"strconv"
)
var db *gorm.DB
var err error
var num int
type Content struct {
	ID int
	WORD string `gorm:"type:varchar(20)"`
}
//定义处理函数
func index(c *gin.Context)  {
	var contents []Content
	err=db.Find(&contents).Error
	if err!=nil {
		c.AbortWithStatus(404)
		fmt.Println(err)
	}else {
		c.HTML(http.StatusOK, "SayHello", gin.H{
			"contents": contents,
		})
	}

}
func input(c *gin.Context){
	content:=c.PostForm("content")
	v:=Content{num,content}
	db.Create(&v)
	num++
	c.Redirect(http.StatusMovedPermanently,"/")

}
func del(c *gin.Context){
	var v Content
	arg:= c.Param("i")
	i, _ :=strconv.Atoi(arg[1:])
	err=db.Where("ID=?",i).Delete(&v).Error
	c.Redirect(http.StatusMovedPermanently,"/")
}
//添加中间件
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method      //请求方法
		origin := c.Request.Header.Get("Origin")        //请求头部
		var headerKeys []string                             // 声明请求头keys
		for k, _ := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			c.Header("Access-Control-Allow-Origin", "*")        // 这是允许访问所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")      //服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
			//  header的类型
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			//              允许跨域设置                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")      // 跨域关键设置 让浏览器可以解析
			c.Header("Access-Control-Max-Age", "172800")        // 缓存请求信息 单位为秒
			c.Header("Access-Control-Allow-Credentials", "false")       //  跨域请求是否需要带cookie信息 默认设置为true
			c.Set("content-type", "application/json")       // 设置返回格式是json
		}

		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		// 处理请求
		c.Next()        //  处理请求
	}
}


func main(){
	//gin初始化
	gin.SetMode(gin.ReleaseMode)
	router:=gin.Default()
	router.Use(Cors())
	router.StaticFS("/static", http.Dir("./static"))
	router.StaticFile("/favicon.ico", "./static/SayHello.ico")
	router.LoadHTMLGlob("./templates/*")
	//数据库初始化
    //注意:这里的IP地址是Docker MySQL容器中的地址,docker inspect mysql查看IP
	db,err=gorm.Open("mysql","root:root@tcp(172.18.0.2:3306)/SayHello?charset=utf8")
	if err!=nil{
		panic(err)
	}
	defer db.Close()
	//创建表,将结构体与表单映射
	db.AutoMigrate(&Content{})
	//绑定路由
	router.GET("/",index)
	router.POST("/",input)
	router.POST("/del/*i", del)
	_ =router.Run(":9000")
}

3、编写Dockerfile文件

这里最难受的就是Golang的环境配置了,也是因为我对GOROOT和GOPATH等没理解清楚,就是搞了好久,最后好不容易解决了,才知道go mod还是舒服啊。

FROM golang
LABEL maintainer=rong<1848224883@qq.com>
COPY . /$GOPATH/src/SayHello/
WORKDIR /$GOPATH/src/SayHello/
#设置环境变量,开启go module和设置下载代理
RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://goproxy.cn,direct
#会在当前目录生成一个go.mod文件用于包管理
RUN go mod init
#增加缺失的包,移除没用的包
RUN go mod tidy
RUN go build app.go
EXPOSE 9000:9000
CMD ["go","run","app.go"]

在当前文件夹下输入docker 命令就可以生成镜像

docker build -t sayhello .

4、部署到阿里云服务器

首先得有一个阿里云账号和云服务器

阿里云注册地址

注册成功后,搜索“容器镜像服务”在这里可以创建自己的镜像仓库,具体操作步骤见阿里云,这里就不多叙述

我之前购买了阿里云高校学生“在家实践”计划的免费服务器,只要是学生并且答对题就可以免费领了,真的非常感谢阿里爸爸,相关内容可以百度

阿里云高校学生在家实践计划

之后使用Xshell6连接云服务器,进行下述操作:

  1. 下载Docker
  2. Docker push 之前上传到自己镜像仓库中的镜像
  3. docker push mysql
  4. docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=YourPassword -v /DockerVolume/mysql/data:/var/lib/mysql mysql,这里可以不用进行端口映射-p 3306:3306
  5. docker run -d --name sayhello --link mysql -p 9000:9000 ImageId
  6. 为服务器设置安全组,允许访问9000端口

至此,这个最简单的项目就算完成了,然后在浏览器输入云服务器IP地址+端口号就可以访问了

所有的源码均已粘贴到文章中,可以直接复制并尝试搭建。

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值