網站首頁 編程語言 正文
需要使用docker將golang的httpserver容器化。在這個過程中遇到了一個低級問題,golang http服務時端口無法訪問,特此記錄解決這個問題的過程。
1.背景
1.1 問題描述
問題描述: docker鏡像啟動成果之后,通過curl不能訪問:
[root@hecs-205828 ~]# curl -XGET http://127.0.0.1:8360/hello
curl: (56) Recv failure: Connection reset by peer
1.2 webserver代碼
go文件:main.go
package main import ( "fmt" "net/http" "os" "strings" ) func main() { http.HandleFunc("/hello", handler_hello) http.HandleFunc("/healthz", handler_healthz) http.ListenAndServe("127.0.0.1:8360", nil) } func handler_healthz(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("OK")) } func handler_hello(w http.ResponseWriter, r *http.Request) { fmt.Println("method = ", r.Method) fmt.Println("URL = ", r.URL) fmt.Println("RemoteAddr = ", r.RemoteAddr) fmt.Println("IP = ", strings.Split(r.RemoteAddr, ":")[0]) fmt.Println("header = ", r.Header) fmt.Println("body = ", r.Body) fmt.Println(r.RemoteAddr, "連接成功") for name, values := range r.Header { for _, value := range values { fmt.Println(name, value) _, exits := w.Header()[name] if exits { w.Header().Add(name, value) } else { w.Header().Set(name, value) } } } VERSION := os.Getenv("VERSION") fmt.Println("VERSION is :", VERSION) w.Header().Set("VERSION", VERSION) w.WriteHeader(http.StatusOK) w.Write([]byte("hello http server")) }
3.Dockerfile文件
Dockerfile文件:
FROM golang:1.17 AS build
WORKDIR /web-server/
COPY . .
ENV CGO_ENABLED=0
ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn,direct
RUN GOOS=linux go build -installsuffix cgo -o web-server main.go
FROM busybox
COPY --from=build /web-server/web-server /web-server/web-server
EXPOSE 8360
ENV ENV local
WORKDIR /web-server/
ENTRYPOINT ["/web-server/web-server"]
2.問題分析
發現curl無法訪問docker容器中的服務,telnet結果如下:
[root@hecs-205828 ~]# telnet 127.0.0.1 8360
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Connection closed by foreign host.
于是,打算采用命令進入docker容器內部查看:
[root@hecs-205828 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dfb2b46abd34 httpserver:0.0.1 "/web-server/web-ser…" 27 hours ago Up 2 hours 0.0.0.0:8360->8360/tcp, :::8360->8360/tcp relaxed_mccarthy
通過docer ps -a 得到容器id為dfb2b46abd34。進入容器:
[root@hecs-205828 ~]# docker exec -it dfb2b46abd34 sh
/web-server # ps
PID USER TIME COMMAND
1 root 0:00 /web-server/web-server
38 root 0:00 sh
94 root 0:00 sh
101 root 0:00 ps
/web-server # netstat -an |grep 8360
tcp 0 0 127.0.0.1:8360 0.0.0.0:* LISTEN
/web-server #
可以看到,在容器內部實際上8360端口已經被監聽。容器訪問應該不存在問題。 容器內部支持wget:
/web-server # wget -q -O - http://127.0.0.1:8360/hello
hello http server
/web-server #
可以看到在docker服務內部運行是正常的。
查看其網絡端口衍射:
[root@hecs-205828 ~]# docker port dfb2b46abd34
8360/tcp -> 0.0.0.0:8360
8360/tcp -> :::8360
端口衍射也不存在問題。那么問題究竟出在什么地方呢? 忽然想到,容器內部的nestat監聽端口是127.0.0.1,于是瞬間明白了。 在容器內部的監聽端口為127.0.0.1的話,那么只能接受容器內部來自127.0.0.1的本地回環訪問。來自容器外外部的訪問請求將被拒絕。 因此,這個問題的修復原因實際上很簡單,只需要將main.go的中監聽ip改為0.0.0.0即可。
3.解決方案
果斷將監聽ip改為0.0.0.0:
func main() { http.HandleFunc("/hello", handler_hello) http.HandleFunc("/healthz", handler_healthz) http.ListenAndServe("0.0.0.0:8360", nil) }
之后重新制作鏡像:
sudo docker build . -t httpserver:0.0.2
然后啟動本地鏡像:
sudo docker run -d -p 8260:8230 httpserver:0.0.2
啟動之后:
[root@hecs-205828 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ae5e2bf431c7 httpserver:0.0.2 "/web-server/web-ser…" 50 minutes ago Up 50 minutes 0.0.0.0:8260->8360/tcp, :::8260->8360/tcp affectionate_nash
dfb2b46abd34 httpserver:0.0.1 "/web-server/web-ser…" 27 hours ago Up 2 hours 0.0.0.0:8360->8360/tcp, :::8360->8360/tcp relaxed_mccarthy
[root@hecs-205828 ~]#
之后再訪問新增的容器,結果正常:
[root@hecs-205828 ~]# curl -XGET http://127.0.0.1:8260/hello
hello http server
[root@hecs-205828 ~]#
問題解決。
原文鏈接:https://juejin.cn/post/7128165664610598943
相關推薦
- 2022-10-16 Pytorch?linear?多維輸入的參數問題_python
- 2022-04-16 C語言數據結構之二分法查找詳解_C 語言
- 2022-07-26 Python使用shutil操作文件、subprocess運行子程序_python
- 2022-03-14 Springboot中遇到的問題——Failed to load ApplicationContex
- 2022-12-03 init?output?stream初始化輸出流源碼分析_Android
- 2022-03-27 PostgreSQL中的日期/時間函數詳解_PostgreSQL
- 2022-06-08 golang操作rocketmq的示例代碼_Golang
- 2022-07-22 SpringBoot允許跨域訪問配置
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支