背景
- 團隊內每個開發(fā)人員PHP版本不一致
- 本地開發(fā)環(huán)境與生產環(huán)境不一致摊滔,環(huán)境不一致易導致生產問題
- 每次新人過來安裝PHP環(huán)境耗時比較長且不可控
目標
- 所有開發(fā)人員環(huán)境保持一致
- 開發(fā)環(huán)境與生產環(huán)境保持一致
- 能快速安裝輕量級的開發(fā)環(huán)境
思路
- 將標準PHP環(huán)境打包靜docker鏡像中砚蓬,所有開發(fā)成員代碼運行在容器里面褪那,本地不需要安裝開發(fā)環(huán)境(除IDE工具外)
- 容器里面提供sshd服務,使開發(fā)者能夠通過ssh登陸并傳輸文件(類似輕量級虛擬機倔既,在容器啟動后利用sftp遠程同步文件比較有用)
構造環(huán)境鏡像
- 版本
linux:alpine3.13
PHP: 7.4
- 準備文件(在后面國建鏡像有用)
nginx主配置文件:nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
#tcp_nopush on;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
include /etc/nginx/conf.d/*.conf;
}
鏡像入口文件(用于啟動鏡像服務): entrypoint.sh
#!/bin/sh
/usr/sbin/sshd -D &
nginx &
php-fpm
- 鏡像Dockerfile
在有了上面兩個文件后牛曹,我們就可以開始構建我們的環(huán)境鏡像了
# 采用基于alpine的php-fpm鏡像(alpine為一個輕量級的linux鏡像)
FROM amd64/php:7.4-fpm-alpine3.13
# 復制PHP配置文件
RUN cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# 由于倉庫鏡像網絡問題谴轮,換成阿里云資源
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 安裝php擴展(可以根據自己的需要安裝所需PHP擴展)
# install-php-extensions使用文檔:
# https://github.com/mlocati/docker-php-extension-installer
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions
RUN install-php-extensions swoole
RUN install-php-extensions mongodb
RUN install-php-extensions redis
RUN install-php-extensions rdkafka
RUN install-php-extensions bcmath
RUN install-php-extensions pdo_mysql
# 安裝composer
RUN php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer
# alpine利用apk進行系統(tǒng)包管理
# 更新apk庫并安裝時區(qū)數據庫、sshd服務识窿、nginx
RUN apk update && apk add tzdata openssh nginx
# 配置時區(qū)(alpine默認時區(qū)為0時區(qū)斩郎,與北京時間相差8小時,需要調整為Asia/Shanghai)
ENV TIME_ZONE=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && echo $TIME_ZONE > /etc/timezone
# 安裝openssh喻频,容器啟動后可以通過ssh登陸或傳輸文件
# 初始賬號密碼為root:123456
RUN sed -i "s/#PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config &&\
ssh-keygen -t dsa -P "" -f /etc/ssh/ssh_host_dsa_key &&\
ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key &&\
ssh-keygen -t ecdsa -P "" -f /etc/ssh/ssh_host_ecdsa_key &&\
ssh-keygen -t ed25519 -P "" -f /etc/ssh/ssh_host_ed25519_key &&\
echo "root:123456" | chpasswd
# 配置nginx主配置文件
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /data/entrypoint.sh
# 安裝swoft開發(fā)工具(swoft框架的開發(fā)工具缩宜,如果沒有用到則不需要安裝)
RUN wget https://github.com/swoft-cloud/swoft-cli/releases/download/v0.2.1/swoftcli.phar &&\
mv swoftcli.phar /usr/local/bin/swoftcli &&\
chmod a+x /usr/local/bin/swoftcli
# 設置默認工作目錄
WORKDIR /data/web/
# 暴露端口
EXPOSE 22
EXPOSE 80
EXPOSE 9000
# 啟動sshd、nginx半抱、fpm
CMD ["sh","/data/entrypoint.sh"]
構建鏡像
docker build -t jeanslin/php7.4-dev .
查看構建后的鏡像
運行環(huán)境
- 啟動容器
此處可以將存放代碼的目錄掛載到容器里面脓恕,這樣宿主機和容器的代碼就是相同的
docker run -d
-p 10080:80 -p 10022:22 -p 19000:9000
-v /Users/it/project:/data/web/project
jeanslin/php7.4-dev
-
利用ssh登陸容器
由于我們把容器的22端口映射到宿主機的10022端口,通過10022端口就可以登陸容器里面
查看已啟動的服務進程窿侈,可以看到已啟動了php-fpm炼幔、nginx、sshd服務
- 配置后端nginx文件:api.conf
由于容器只對外開放了80端口史简,為了區(qū)分不同的服務乃秀,我們可以在宿主機/etc/hosts文件配置開發(fā)域名來映射到容器的不同服務肛著,此處將api.dev.com映射到127.0.0.1
server {
listen 80;
server_name api.dev.com;
root /data/web/;
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SERVER_NAME $http_host;
fastcgi_ignore_client_abort on;
}
}
我們在容器的/data/web/寫一個phpinfo.php的腳本文件,用來調試服務是否正常
<?php
phpinfo();
由于容器的80端口是掛載到宿主機的10080端口跺讯,我們通過該端口訪問服務
訪問地址為:http://api.dev.com:10080/phpinfo.php
- 配置前端nginx文件:web.conf
在宿主機/etc/hosts文件將web.dev.com映射到127.0.0.1
此處為了解決前端跨域問題枢贿,將/api/開頭的路徑轉發(fā)到api.dev.com
server {
listen 80;
server_name web.dev.com;
root /data/web/;
location / {
index index.php index.html index.htm;
try_files $uri $uri/ /index.html;
}
location ^~/api/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://@back/;
}
}
upstream @back{
server api.dev.com;
}
我們在容器/data/web/目錄創(chuàng)建一個index.html文件,內容如下
<html>
<body>
nice to meet you!
</body>
</html>
由于容器的80端口是掛載到宿主機的10080端口刀脏,我們通過該端口訪問服務
訪問地址為:http://web.dev.com:10080/index.html
至此局荚,開發(fā)者本地nginx+php-fpm的開發(fā)環(huán)境已經準備完成,開發(fā)者通過拉取該鏡像使用即可(開發(fā)者本地需要安裝docker)愈污,本地無需安裝任何環(huán)境軟件耀态。
遠程開發(fā)
除上面的場景外,還可以用于以下場景
我們還可以在一臺開發(fā)機上為每個開發(fā)者創(chuàng)建一個容器暂雹,然后開發(fā)者可以通過ssh服務遠程登錄到容器里面首装,這樣開發(fā)者本地docker也不需要安裝
在一些swoole框架,比如swoft需要讀取文件注解的杭跪,如果通過掛載的方式把代碼掛到容器里面仙逻,在代碼變更熱重啟時會很慢,影響開發(fā)體驗涧尿,這時可以通過ssh自帶sftp服務直接將代碼直接同步到容器里面系奉,這樣容器熱重啟會快許多
以下我們基于swoft框架,用phpstorm演示一下如何遠程開發(fā)容器里面的代碼:
入口為:tools > Deployment > Configuration
配置connection姑廉,此處容器的22端口掛載到宿主機的10022端口喜最,我們通過宿主機的10022連接容器
我們添加一個Mappings,將本地的文件/Users/linjunda/it/tme/doc/doc_service同步到容器的/data/web/
tools > Deployment > Automatic upload 選擇為always庄蹋,該選項表示如果目錄代碼發(fā)生變更則自動同步到遠程服務器
我們先執(zhí)行一次全量的同步瞬内,入口為:tools > Deployment > Sync with deployed to
控制臺顯示文件同步完成信息
現(xiàn)在我們可以在容器里面啟動這個swoft服務的熱重啟監(jiān)聽
此處容器里面doc_service服務的監(jiān)聽為1007,我們通過nginx配置進行端口轉發(fā)
server {
listen 80;
server_name doc.dev.com;
root /data/web/;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://@docBack/;
}
}
upstream @docBack{
server localhost:1007;
}
我們寫一個TestController
/**
* @Controller(prefix="test")
*/
class TestController
{
/**
* @RequestMapping(route="test")
*/
public function test(Response $response)
{
return $response->withContent("hello world");
}
}
此處我們將doc.dev.com域名的所有請求轉發(fā)到1007端口下面限书,通過宿主機訪問如下
現(xiàn)在我們再IDE修改腳本文件后就會遠程同步到容器里面虫蝶,容器里面的swoft熱重啟服務監(jiān)聽到文件變化時會觸發(fā)服務重啟,這樣我們就相當于遠程在調試容器里面的代碼了倦西。
接下來我們在本地IDE把返回內容改為“nice to meet you!”能真,再訪問原來的地址,內容如下:
以上就是本次的一些分享扰柠,如果轉載請標明遠處粉铐,覺得對你有幫助的話,請點個贊吧 _