Docker部署Gin项目初体验

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

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

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

目录

1、前端设计

2、后端实现

3、编写Dockerfile文件

4、部署到阿里云服务器


项目目录:

SayHello

|Docker部署Gin项目初体验_第1张图片

步骤如下:

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




    
    
    SayHello
    
    
    


Say Hello

to the World

{{ range $i,$value:=.contents }} {{ if $value.WORD }}
  • {{ $value.WORD }}
  • {{end}} {{ end }}

    Docker部署Gin项目初体验_第2张图片

    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<[email protected]>
    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地址+端口号就可以访问了

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

     

    你可能感兴趣的:(Gin,docker,go,web)