<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    部署一個(gè) Go 應(yīng)用的正確姿勢(shì)

    共 4686字,需瀏覽 10分鐘

     ·

    2020-06-18 23:24

    點(diǎn)擊上方藍(lán)色“Go語(yǔ)言中文網(wǎng)”關(guān)注我們,領(lǐng)全套Go資料,每天學(xué)習(xí)?Go?語(yǔ)言

    有些新手寫(xiě)完了他們的 Go 應(yīng)用之后,這總會(huì)成為一個(gè)大問(wèn)題——“我剛寫(xiě)的這個(gè) Go 應(yīng)用,當(dāng)它崩潰的時(shí)候我要怎么重啟?”,因?yàn)槟銢](méi)法用 go run main.go 或者 ./main 這樣的命令讓它持續(xù)運(yùn)行,并且當(dāng)程序崩潰的時(shí)候能夠重啟。

    一個(gè)普通使用的好辦法是使用 Docker。但是,設(shè)置 Docker 以及為容器配置你的應(yīng)用需要花費(fèi)時(shí)間,當(dāng)你的程序需要和 MySQL、Redis 這樣的服務(wù)器/進(jìn)程交互時(shí)更是如此。對(duì)于一個(gè)大型或長(zhǎng)期項(xiàng)目來(lái)說(shuō),毋庸置疑這是一個(gè)正確的選擇。但是如果在你手上的是個(gè)小應(yīng)用,你想要快速部署并且實(shí)時(shí)地服務(wù)器上查看狀態(tài),那么你可能需要考慮別的選擇。

    另一個(gè)選擇就是在你的 Linux 服務(wù)器上創(chuàng)建一個(gè)守護(hù)進(jìn)程,然后讓它作為一個(gè)服務(wù)運(yùn)行,但是這需要花費(fèi)一些額外的工夫。而且,如果你并不具備 Linux 系統(tǒng)和服務(wù)相關(guān)的知識(shí)的話,這就不是一件簡(jiǎn)單的事情了。所以,這里有一個(gè)最簡(jiǎn)單的解決方案——使用 Supervisor[1] 來(lái)部署你的 Go 應(yīng)用,然后它會(huì)為你處理好其余的工作。它是一個(gè)能夠幫你監(jiān)控你的應(yīng)用程序并在其崩潰時(shí)進(jìn)行重啟的工具。

    安裝

    安裝 Supervisor 相當(dāng)簡(jiǎn)單,在 Ubuntu 上這條命令就會(huì)在你的系統(tǒng)上安裝 Supervisor。

    sudo?apt?install?supervisor

    然后你需要將 Supervisor 添加到系統(tǒng)的用戶組中:

    sudo?addgroup?--system?supervisor

    現(xiàn)在,在創(chuàng)建 Supervisor 的配置文件之前,我們先寫(xiě)一個(gè)簡(jiǎn)單的 Go 程序。這個(gè)程序?qū)?huì)讀取 .env 文件中的配置項(xiàng),然后和 MySQL 數(shù)據(jù)庫(kù)進(jìn)行交互。代碼如下:

    (為了方便演示,我們會(huì)讓代碼簡(jiǎn)單些)

    package?main

    import?(
    ?"database/sql"
    ?"encoding/json"
    ?"fmt"
    ?"log"
    ?"net/http"
    ?"os"

    ?_?"github.com/go-sql-driver/mysql"
    ?"github.com/gorilla/mux"
    ?"github.com/joho/godotenv"
    )

    type?User?struct?{
    ?Email????string?`json:"email"`
    ?Password?string?`json:"password"`
    }

    var?db?*sql.DB

    func?init()?{
    ?var?err?error
    ?err?=?godotenv.Load()
    ?if?err?!=?nil?{
    ??log.Println("Error?readin?.env:?",?err)
    ??os.Exit(1)
    ?}

    ?dbUserName?:=?os.Getenv("DB_USERNAME")
    ?dbPassword?:=?os.Getenv("DB_PASSWORD")
    ?dbNAME?:=?os.Getenv("DB_NAME")

    ?dsn?:=?dbUserName?+?":"?+?dbPassword?+?"@/"?+?dbNAME

    ?db,?err?=?sql.Open("mysql",?dsn)

    ?if?err?!=?nil?{
    ??log.Println(err)
    ??os.Exit(1)
    ?}

    }

    func?main()?{

    ?r?:=?mux.NewRouter()

    ?r.Use(middleware)

    ?r.HandleFunc("/",?rootHandler)
    ?r.HandleFunc("/user",?createUserHandler).Methods("POST")

    ?fmt.Println("Listening?on?:8070")
    ?if?err?:=?http.ListenAndServe(":8070",?r);?err?!=?nil?{
    ??//?退出程序
    ??log.Println("Failed?starting?server?",?err)
    ??os.Exit(1)
    ?}

    }

    func?rootHandler(w?http.ResponseWriter,?r?*http.Request)?{
    ?fmt.Fprintf(w,?"This?is?root?handler")
    }

    func?createUserHandler(w?http.ResponseWriter,?r?*http.Request)?{

    ?user?:=?&User{}

    ?err?:=?json.NewDecoder(r.Body).Decode(user)

    ????//?對(duì)請(qǐng)求響應(yīng)?JSON?數(shù)據(jù)
    ????//?在實(shí)際應(yīng)用中你可能想要?jiǎng)?chuàng)建一個(gè)進(jìn)行錯(cuò)誤處理的函數(shù)
    ?if?err?!=?nil?{
    ??//?我們也可以這么做
    ??//?errREsp?:=?`"error":?"Invalid?input",?"status":?400`
    ??//?w.Header().Set("Content-Type",?"application/json")
    ??//?w.WriteHeader(400)
    ????????//?w.Write([]byte(errREsp))

    ????????//?然而我們會(huì)讓服務(wù)器崩潰
    ??log.Fatal(err)

    ??return
    ?}

    ????//?在實(shí)際應(yīng)用中必須對(duì)密碼進(jìn)行哈希,可以使用?bcrypt?算法
    ?_,?err?=?db.Exec("INSERT?INTO?users(email,?password)?VALUES(?,?)",?user.Email,?user.Password)

    ?if?err?!=?nil?{
    ??log.Println(err)
    ????????//?簡(jiǎn)單起見(jiàn),發(fā)送明文字符串
    ????????//?創(chuàng)建一個(gè)有效的?JSON?響應(yīng)
    ??errREsp?:=?`"error":?"Internal?error",?"status":?500`?//?返回?500?狀態(tài)碼,因?yàn)檫@是我們而非用戶的問(wèn)題
    ??w.Header().Set("Content-Type",?"application/json")
    ??w.WriteHeader(500)
    ??w.Write([]byte(errREsp))

    ??return
    ?}

    }

    //?一個(gè)簡(jiǎn)單的中間件,只用來(lái)記錄請(qǐng)求的?URI
    var?middleware?=?func(next?http.Handler)?http.Handler?{

    ?return?http.HandlerFunc(func(w?http.ResponseWriter,?r?*http.Request)?{

    ??requestPath?:=?r.URL.Path
    ??log.Println(requestPath)
    ??next.ServeHTTP(w,?r)?//?在中間件調(diào)用鏈中進(jìn)行處理!

    ?})
    }

    現(xiàn)在,如果我們想要用 Supervisor 來(lái)運(yùn)行這個(gè)程序,我們需要構(gòu)建程序的二進(jìn)制文件。同時(shí)在項(xiàng)目的根目錄下創(chuàng)建一個(gè) .env 文件 —— 如果你想把配置文件和項(xiàng)目放在一起的話,在這個(gè)文件中寫(xiě)上 MySQL 數(shù)據(jù)庫(kù)需要的變量。

    將這個(gè)倉(cāng)庫(kù)克隆到你想要運(yùn)行的服務(wù)器上。確保你遵循了 Go 目錄路徑的慣例:

    $?go?build?.

    Go 的這個(gè)命令最終會(huì)創(chuàng)建一個(gè)以項(xiàng)目根目錄命名的二進(jìn)制文件,所以如果項(xiàng)目的根目錄是 myapp,那么文件的名稱就是 myapp。

    現(xiàn)在,在服務(wù)器上創(chuàng)建 Supervisor 的配置文件 /etc/supervisor/conf.d。

    #/etc/supervisor/conf.d/myapp.conf

    [program:myapp]
    directory=/root/gocode/src/github.com/monirz/myapp
    command=/root/gocode/src/github.com/monirz/myapp/myapp
    autostart=true
    autorestart=true
    stderr_logfile=/var/log/myapp.err
    stdout_logfile=/var/log/myapp.log
    environment=CODENATION_ENV=prod
    environment=GOPATH="/root/gocode"

    這里的 directory 和 command 變量很重要。directory 變量應(yīng)該設(shè)置為項(xiàng)目的根目錄,因?yàn)槌绦驅(qū)?huì)嘗試在 directory 指定的路徑下讀取 .env 文件或是其他需要的配置文件。autorestart 變量設(shè)置為 true,這樣當(dāng)程序崩潰時(shí)就會(huì)重啟。

    現(xiàn)在通過(guò)下面的命令重新加載 Supervisor:

    $?sudo?supervisorctl?reload

    來(lái)檢查下它的狀態(tài)。

    $?sudo?supervisorctl?status

    一切都正確配置的話,你應(yīng)該會(huì)看到類似下面的輸出內(nèi)容:

    myapp?????RUNNING???pid?2023,?uptime?0:00:03

    我們名為 myapp 的 Go 服務(wù)端程序正在后臺(tái)運(yùn)行。

    現(xiàn)在向我們剛寫(xiě)的 API 發(fā)起一些請(qǐng)求。首先檢查 rootHandler 是否正在工作。然后向 /user 結(jié)點(diǎn)發(fā)送一個(gè)包含無(wú)效 JSON 格式數(shù)據(jù)的請(qǐng)求。這應(yīng)當(dāng)會(huì)讓服務(wù)器崩潰。但是服務(wù)器上沒(méi)有存儲(chǔ)任何日志,不是嗎?因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)日志功能?

    等等,Supervisor 實(shí)際上已經(jīng)為我們處理了日志。如果你到 /var/log 目錄下查看 myapp.log 文件,你就會(huì)看到它記錄著已經(jīng)向服務(wù)器發(fā)起過(guò)的請(qǐng)求的 URI 路徑。

    $?cat?/var/log/myapp.log

    錯(cuò)誤日志也是如此。好了,我們的服務(wù)器程序已經(jīng)運(yùn)行了——崩潰的話會(huì)重啟,還會(huì)記錄每個(gè)請(qǐng)求和錯(cuò)誤信息。我覺(jué)得我們應(yīng)該是在大約 5 分鐘以內(nèi)做完了這些事吧?(大概是吧,誰(shuí)在乎呢。)但關(guān)鍵是,用 Supervisor 來(lái)部署和監(jiān)控你的 Go 應(yīng)用程序時(shí)十分簡(jiǎn)單的。

    你覺(jué)得呢?毫不猶豫地回復(fù)我吧。周末愉快。


    via: https://medium.com/@monirz/deploy-golang-app-in-5-minutes-ff354954fa8e

    作者:Monir Zaman[2]譯者:maxwellhertz[3]校對(duì):polaris1119[4]

    本文由 GCTT[5] 原創(chuàng)編譯,Go 中文網(wǎng)[6] 榮譽(yù)推出

    參考資料

    [1]

    Supervisor: http://supervisord.org/

    [2]

    Monir Zaman: https://medium.com/@monirz

    [3]

    maxwellhertz: https://github.com/maxwellhertz

    [4]

    polaris1119: https://github.com/polaris1119

    [5]

    GCTT: https://github.com/studygolang/GCTT

    [6]

    Go 中文網(wǎng): https://studygolang.com/


    推薦閱讀



    喜歡本文的朋友,歡迎關(guān)注“Go語(yǔ)言中文網(wǎng)

    Go語(yǔ)言中文網(wǎng)啟用微信學(xué)習(xí)交流群,歡迎加微信:274768166,投稿亦歡迎


    瀏覽 33
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    亚洲第一网站视频 | 逼操操| 操屄网站在线观看 | 成人色天堂 | 国产黄色免费视频 |