Projector
总所周知,vscode这款轻量编辑器最吸引人的地方就是有一个remote开发的插件,通过这个remote的插件可以连接上远程的linux主机,比如阿里云或者腾讯云的轻量应用服务,然后构建一个比较通用的开发环境,但是vscode这款编辑器太轻量级了,导致我个人使用感受来说,代码提示和高亮的插件会比较慢,而且配置起来不是很方便,比如cpp的开发配置,需要配置几个json文件放在当前目录的.vscode下面才能进行正确的语法提示,通常需要指定gcc或者clang的stl或者是其他的库文件的路径,才能#include进来进行相对提示。而Java想在vscode上开发,是一件更难的事情,毕竟jetbrains的idea才是王道。Projector的地址为lp.jetbrains.com/projector/。
在linux中搭建Projector
- 找到对应的projector源码,github.com/JetBrains/p… 在projector的源码的md中可以看到jetbrains提供了官方编译好的镜像文件供大家使用
本文不使用jetbrains官方提供的镜像,因为这些镜像使用的是debian作为base-image的,并且所使用的的idea版本也是相对老旧,是2020的版本,本文构建基于centos8和idea-2021.3的projector远程开发镜像
- 在提供镜像的下方有一个如何自定义镜像的一个说明
我们主要看这3个bash文件,这3个bash的作用在下方注释
# clone-projector-core.sh 主要是把远程server的代码拉到本地,用于后续的镜像构建
set -e # Any command which returns non-zero exit code will cause this shell script to exit immediately
set -x # Activate debugging to show execution details: all commands will be printed before execution
git clone https://github.com/JetBrains/projector-server.git ../projector-server
# build-container.sh 从jebtrains官网的下载链接中下载idea的压缩文件,然后使用docker构建,核心在Dockerfile
containerName=${1:-projector-idea-c}
downloadUrl=${2:-https://download.jetbrains.com/idea/ideaIC-2019.3.5.tar.gz}
# build container:
DOCKER_BUILDKIT=1 docker build --progress=plain -t "$containerName" --build-arg buildGradle=true --build-arg "downloadUrl=$downloadUrl" -f Dockerfile ..
# run-container.sh 这个就是简单run一个docker镜像,没什么好说的
set -e # Any command which returns non-zero exit code will cause this shell script to exit immediately
set -x # Activate debugging to show execution details: all commands will be printed before execution
containerName=${1:-projector-idea-c}
docker run --rm -p 8887:8887 -it "$containerName"
- 核心文件dockerfile(含注释)
FROM debian AS ideDownloader #使用debian作为下载idea的tar包的基础镜像,以下命令就是在下载idea的tar
# prepare tools:
RUN apt-get update
RUN apt-get install wget -y
# download IDE to the /ide dir:
WORKDIR /download
ARG downloadUrl
RUN wget -q $downloadUrl -O - | tar -xz
RUN find . -maxdepth 1 -type d -name * -execdir mv {} /ide \;
FROM amazoncorretto:11 as projectorGradleBuilder #使用amazoncorretto作为prjector-core的编译镜像,然后使用gradel编译projector-server
ENV PROJECTOR_DIR /projector
# projector-server:
ADD projector-server $PROJECTOR_DIR/projector-server
WORKDIR $PROJECTOR_DIR/projector-server
ARG buildGradle
RUN if [ "$buildGradle" = "true" ]; then ./gradlew clean; else echo "Skipping gradle build"; fi
RUN if [ "$buildGradle" = "true" ]; then ./gradlew :projector-server:distZip; else echo "Skipping gradle build"; fi
RUN cd projector-server/build/distributions && find . -maxdepth 1 -type f -name projector-server-*.zip -exec mv {} projector-server.zip \;
FROM debian AS projectorStaticFiles #执行了一些文件的处理操作和idea启动相关
# prepare tools:
RUN apt-get update
RUN apt-get install unzip -y
# create the Projector dir:
ENV PROJECTOR_DIR /projector
RUN mkdir -p $PROJECTOR_DIR
# copy IDE:
COPY --from=ideDownloader /ide $PROJECTOR_DIR/ide
# copy projector files to the container:
ADD projector-docker/static $PROJECTOR_DIR
# copy projector:
COPY --from=projectorGradleBuilder $PROJECTOR_DIR/projector-server/projector-server/build/distributions/projector-server.zip $PROJECTOR_DIR
# prepare IDE - apply projector-server:
RUN unzip $PROJECTOR_DIR/projector-server.zip
RUN rm $PROJECTOR_DIR/projector-server.zip
RUN find . -maxdepth 1 -type d -name projector-server-* -exec mv {} projector-server \;
RUN mv projector-server $PROJECTOR_DIR/ide/projector-server
RUN mv $PROJECTOR_DIR/ide-projector-launcher.sh $PROJECTOR_DIR/ide/bin
RUN chmod 644 $PROJECTOR_DIR/ide/projector-server/lib/*
FROM debian:10 #构建了idea的运行环境,基于debian的环境,然后安装了awt需要的各种so动态库环境,然后把8887端口暴露出去,启动docker镜像是执行run.sh文件
RUN true \
# Any command which returns non-zero exit code will cause this shell script to exit immediately:
&& set -e \
# Activate debugging to show execution details: all commands will be printed before execution
&& set -x \
# install packages:
&& apt-get update \
# packages for awt:
&& apt-get install libxext6 libxrender1 libxtst6 libxi6 libfreetype6 -y \
# packages for user convenience:
&& apt-get install git bash-completion sudo -y \
# packages for IDEA (to disable warnings):
&& apt-get install procps -y \
# clean apt to reduce image size:
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/cache/apt
ARG downloadUrl
RUN true \
# Any command which returns non-zero exit code will cause this shell script to exit immediately:
&& set -e \
# Activate debugging to show execution details: all commands will be printed before execution
&& set -x \
# install specific packages for IDEs:
&& apt-get update \
&& if [ "${downloadUrl#*CLion}" != "$downloadUrl" ]; then apt-get install build-essential clang -y; else echo "Not CLion"; fi \
&& if [ "${downloadUrl#*pycharm}" != "$downloadUrl" ]; then apt-get install python2 python3 python3-distutils python3-pip python3-setuptools -y; else echo "Not pycharm"; fi \
&& if [ "${downloadUrl#*rider}" != "$downloadUrl" ]; then apt install apt-transport-https dirmngr gnupg ca-certificates -y && apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && echo "deb https://download.mono-project.com/repo/debian stable-buster main" | tee /etc/apt/sources.list.d/mono-official-stable.list && apt update && apt install mono-devel -y && apt install wget -y && wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb && apt-get update && apt-get install -y apt-transport-https && apt-get update && apt-get install -y dotnet-sdk-3.1 aspnetcore-runtime-3.1; else echo "Not rider"; fi \
# clean apt to reduce image size:
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /var/cache/apt
# copy the Projector dir:
ENV PROJECTOR_DIR /projector
COPY --from=projectorStaticFiles $PROJECTOR_DIR $PROJECTOR_DIR
ENV PROJECTOR_USER_NAME projector-user
RUN true \
# Any command which returns non-zero exit code will cause this shell script to exit immediately:
&& set -e \
# Activate debugging to show execution details: all commands will be printed before execution
&& set -x \
# move run scipt:
&& mv $PROJECTOR_DIR/run.sh run.sh \
# change user to non-root (http://pjdietz.com/2016/08/28/nginx-in-docker-without-root.html):
&& mv $PROJECTOR_DIR/$PROJECTOR_USER_NAME /home \
&& useradd -d /home/$PROJECTOR_USER_NAME -s /bin/bash -G sudo $PROJECTOR_USER_NAME \
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \
&& chown -R $PROJECTOR_USER_NAME.$PROJECTOR_USER_NAME /home/$PROJECTOR_USER_NAME \
&& chown -R $PROJECTOR_USER_NAME.$PROJECTOR_USER_NAME $PROJECTOR_DIR/ide/bin \
&& chown $PROJECTOR_USER_NAME.$PROJECTOR_USER_NAME run.sh
USER $PROJECTOR_USER_NAME
ENV HOME /home/$PROJECTOR_USER_NAME
EXPOSE 8887
CMD ["bash", "-c", "/run.sh"]
- 看完了上面的这4个文件,其实想要构建centos8 + idea最新版本已经很明了了,在build_container.sh里修改最新的idea下载链接或者是jetbrains其他全家桶,连接如下
注意选用linux版本
接着需要修稿dockerfile里面的baseimage和其中的一些环境搭建的命令。具体文件如下
# build_container.sh 修改过后的sh文件
set -e # Any command which returns non-zero exit code will cause this shell script to exit immediately
set -x # Activate debugging to show execution details: all commands will be printed before execution
containerName=${1:-projector-idea-u}
downloadUrl=${2:-https://download.jetbrains.com/idea/ideaIU-2021.2.3.tar.gz}
# build container:
DOCKER_BUILDKIT=1 docker build --progress=plain -t "$containerName" --build-arg buildGradle=true --build-arg "downloadUrl=$downloadUrl" -f Dockerfile ..
FROM debian AS ideDownloader
# prepare tools:
RUN apt-get update
RUN apt-get install wget -y
# download IDE to the /ide dir:
WORKDIR /download
ARG downloadUrl
RUN wget -q $downloadUrl -O - | tar -xz
RUN find . -maxdepth 1 -type d -name * -execdir mv {} /ide \;
FROM amazoncorretto:11 as projectorGradleBuilder
ENV PROJECTOR_DIR /projector
# projector-server:
ADD ../projector-server $PROJECTOR_DIR/projector-server
WORKDIR $PROJECTOR_DIR/projector-server
ARG buildGradle
RUN if [ "$buildGradle" = "true" ]; then ./gradlew clean; else echo "Skipping gradle build"; fi
RUN if [ "$buildGradle" = "true" ]; then ./gradlew :projector-server:distZip; else echo "Skipping gradle build"; fi
RUN cd projector-server/build/distributions && find . -maxdepth 1 -type f -name projector-server-*.zip -exec mv {} projector-server.zip \;
FROM debian AS projectorStaticFiles
# prepare tools:
RUN apt-get update
RUN apt-get install unzip -y
# create the Projector dir:
ENV PROJECTOR_DIR /projector
RUN mkdir -p $PROJECTOR_DIR
# copy IDE:
COPY --from=ideDownloader /ide $PROJECTOR_DIR/ide
# copy projector files to the container:
ADD projector-docker/static $PROJECTOR_DIR
# copy projector:
COPY --from=projectorGradleBuilder $PROJECTOR_DIR/projector-server/projector-server/build/distributions/projector-server.zip $PROJECTOR_DIR
# prepare IDE - apply projector-server:
RUN unzip $PROJECTOR_DIR/projector-server.zip
RUN rm $PROJECTOR_DIR/projector-server.zip
RUN find . -maxdepth 1 -type d -name projector-server-* -exec mv {} projector-server \;
RUN mv projector-server $PROJECTOR_DIR/ide/projector-server
RUN mv $PROJECTOR_DIR/ide-projector-launcher.sh $PROJECTOR_DIR/ide/bin
RUN chmod 644 $PROJECTOR_DIR/ide/projector-server/lib/*
FROM centos:centos8.1.1911 #这里是重点
RUN true \
# Any command which returns non-zero exit code will cause this shell script to exit immediately:
&& set -e \
# Activate debugging to show execution details: all commands will be printed before execution
&& set -x \
# install packages:
&& yum update -y \
# packages for awt:
# && yum install libxext6 libxrender1 libxtst6 libxi6 libfreetype6 -y \
&& yum install libXtst.i686 libXtst libXext.x86_64 libXrender.x86_64 libXtst.x86_64 freetype -y \
# packages for user convenience:
&& yum install git bash-completion -y \
# packages for IDEA (to disable warnings):
&& yum install procps -y
# clean apt to reduce image size:
# && rm -rf /var/lib/apt/lists/* \
# && rm -rf /var/cache/apt
ARG downloadUrl
RUN true \
# Any command which returns non-zero exit code will cause this shell script to exit immediately:
&& set -e \
# Activate debugging to show execution details: all commands will be printed before execution
&& set -x \
# install specific packages for IDEs:
&& yum update \
&& if [ "${downloadUrl#*CLion}" != "$downloadUrl" ]; then yum install build-essential clang -y; else echo "Not CLion"; fi \
&& if [ "${downloadUrl#*pycharm}" != "$downloadUrl" ]; then yum install python2 python3 python3-distutils python3-pip python3-setuptools -y; else echo "Not pycharm"; fi
# clean apt to reduce image size:
# && rm -rf /var/lib/apt/lists/* \
# && rm -rf /var/cache/apt
# copy the Projector dir:
ENV PROJECTOR_DIR /projector
COPY --from=projectorStaticFiles $PROJECTOR_DIR $PROJECTOR_DIR
ENV PROJECTOR_USER_NAME projector-user
RUN true \
# Any command which returns non-zero exit code will cause this shell script to exit immediately:
&& set -e \
# Activate debugging to show execution details: all commands will be printed before execution
&& set -x \
# move run scipt:
&& mv $PROJECTOR_DIR/run.sh run.sh \
# change user to non-root (http://pjdietz.com/2016/08/28/nginx-in-docker-without-root.html):
&& mv $PROJECTOR_DIR/$PROJECTOR_USER_NAME /home \
&& useradd -m -d /home/$PROJECTOR_USER_NAME -s /bin/bash $PROJECTOR_USER_NAME \
&& chown -R $PROJECTOR_USER_NAME.$PROJECTOR_USER_NAME /home/$PROJECTOR_USER_NAME \
&& chown -R $PROJECTOR_USER_NAME.$PROJECTOR_USER_NAME $PROJECTOR_DIR/ide/bin \
&& chown $PROJECTOR_USER_NAME.$PROJECTOR_USER_NAME run.sh
USER $PROJECTOR_USER_NAME
ENV HOME /home/$PROJECTOR_USER_NAME
EXPOSE 8887
CMD ["bash", "-c", "/run.sh"]
- 然后执行官方md的3个指令
./clone-projector-core.sh
./build-container.sh
./run-container.sh
然后容器就成功启动了!通过vscode的端口转发设置一下,然后访问127.0.0.1:8887就可以访问到远程的idea了,这个idea的使用体验取决于带宽和延迟!
基于上述镜像的二次开发
上面镜像构建了一个没有任何java环境和编译环境的idea远程镜像,现在基于上面构造的镜像构建一个java8和bazel的开发环境,dockefile如下
FROM hkzhao123/centos-idea
user root
#复制本地的ssh秘钥,方便拉git
run mkdir -p /root/.ssh
copy .ssh/* /root/.ssh/
#指定bazel的安装路径在/usr/bin下
env HOME=/usr
env JAVA_HOME=/usr/java/jdk1.8.0_311-i586
env JRE_HOME=/usr/java/jdk1.8.0_311-i586/jre
#指定projector的默认目录为/home/projector-user
WORKDIR /home/projector-user
#修改yum的配置 让Yum不报错
run rm -f /var/lib/rpm/__db.*
run rpm --rebuilddb
#安装需要的依赖
run yum -y install wget
run yum -y install gcc
run wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.cloud.tencent.com/repo/centos8_base.repo
run yum clean all
run yum makecache
#安装oraclejdk
copy ./jdk-8u311-linux-i586.rpm /home/projector-user/
run yum localinstall -y jdk-8u311-linux-i586.rpm
run yum -y install vim
run sed -e '1i\\JAVA_HOME=/usr/java/jdk1.8.0_311-i586\nJRE_HOME=/usr/java/jdk1.8.0_311-i586/jre\nPATH=$PATH:$JAVA_HOME/bin\nCLASSPATH=.:$JAVA_HOME/lib\nHOME=/usr\nexport JAVA_HOME CLASSPATH HOME' /etc/profile | tee /etc/profile > /dev/null
#source在dockerfile里没啥用,可以进去容器source一遍或者加在docker的env上
run source /etc/profile
#也是起到一个source的作用
run sed '$a\\source /etc/profile' /root/.bashrc | tee /root/.bashrc > /dev/null
run source /root/.bashrc
#安装bazel 由于设置了env 所以默认安装在/usr/bin下
run yum install -y unzip
run wget https://github.com/bazelbuild/bazel/releases/download/4.2.0/bazel-4.2.0-installer-linux-x86_64.sh
run chmod +x bazel-4.2.0-installer-linux-x86_64.sh
run ./bazel-4.2.0-installer-linux-x86_64.sh --user
run rm bazel-4.2.0-installer-linux-x86_64.sh
run bazel --version
#安装git 和 git-lfs lfs大文件专用
run yum install -y git
run curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh | bash
run yum install git-lfs -y
run git lfs install
run rm -rf *.sh
run git config --global user.name "hk"
run git config --global user.email "hk@tc.com"
上线的dockerfile需要下面的1个文件 jdk-8u311-linux-i586.rpm 这个可以在oracle的官方网站下载,是rpm文件就可以了,将这个rpm文件放在dockefile的同级路径下,最后可以执行
docker build -t hk/idea:v1 .
使用nginx代理这个projector-server的端口
由于在使用途中,projector-server存在以下问题,在http的情况下,ctrl+c\ctrl+v是存在Bug的,这对我们程序员来说是不能接受的问题。因此在projector的issue中发现,使用https能够解决这个问题,所以下文使用nginx构造一个假证书然后使用https连接projector-server来避免http的这个问题。
yum update -y
yum install nginx -y
openssl genrsa -des3 -out server.pass.key 2048
openssl rsa -in server.pass.key -out server.key
openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Shenzhen/L=Shenzhen/O=cetc/OU=cetc/CN=hkz.cetc.cn"
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
rm -rf /etc/nginx/nginx.conf.default
cp server.crt /etc/nginx/server.crt
cp server.csr /etc/nginx/server.csr
cp server.key /etc/nginx/server.key
systemctl start nginx
nginx -t
修改Nginx.conf文件
rm -rf /etc/nginx/nginx.conf
下面是一条命令
echo "worker_processes 1;
events {
worker_connections 1024;
}
http {
# include mime.types;
# default_type application/json;
sendfile on;
keepalive_timeout 300;
gzip on;
server {
listen 443 ssl;
keepalive_timeout 300;
server_name localhost;
location /idea/ {
proxy_pass http://127.0.0.1:8887/;
client_max_body_size 10m; #表示最大上传10M,需要多大设置多大。
#设置主机头和客户端真实地址,以便服务器获取客户端真实IP
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Scheme \$scheme;
}
ssl_certificate server.crt;
ssl_certificate_key server.key;
# #减少点击劫持
add_header X-Frame-Options DENY;
#禁止服务器自动解析资源类型
add_header X-Content-Type-Options nosniff;
# 防XSS攻击
add_header X-Xss-Protection 1;
#优先采取服务器算法
ssl_prefer_server_ciphers on;
#
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
}" > /etc/nginx/nginx.conf
nginx -t
nginx -s reload
然后启动docker镜像,下面使用设置环境变量的启动方式,可以加一个token防止其他人连到自己的idea里
docker run --rm -p 8887:8887 --env ORG_JETBRAINS_PROJECTOR_SERVER_HANDSHAKE_TOKEN=hk --env ORG_JETBRAINS_PROJECTOR_SERVER_RO_HANDSHAKE_TOKEN=hk -v /home/hk/root:/root -v /home/hk/home:/home -it -d hk/idea:v1
然后在chrome浏览器中访问https://127.0.0.1/idea?token=hk, 如果是mac电脑需要采用以下连接的方式信任这个假证书,然后就可以使用projector-launch客户端去连接,不再需要用chrome