SSHPASS
在命令行中想上传文件到远端主机都要先 ssh 登录,知识贫瘠的我手动了很多年今天终于知道了可以用 sshpass 命令先保存密码再做对应操作
1 | # 将dist文件发送到远程 |
然而 MacOS 上默认是不带这个工具的,Homebrew 也无法直接安装,stackoverflow 上找到下面 2 种方法
1 | # 安装的版本要看对应维护的rb脚本指定的是啥 |
现在就可以愉快的上传了
随便写一些开发的经验和生活的感悟
在命令行中想上传文件到远端主机都要先 ssh 登录,知识贫瘠的我手动了很多年今天终于知道了可以用 sshpass 命令先保存密码再做对应操作
1 | # 将dist文件发送到远程 |
然而 MacOS 上默认是不带这个工具的,Homebrew 也无法直接安装,stackoverflow 上找到下面 2 种方法
1 | # 安装的版本要看对应维护的rb脚本指定的是啥 |
现在就可以愉快的上传了
react-native-swiper
Swiper 组件
react-native-webview
WebView 组件
react-native-svg
配合react-native-svg-transformer可以编写 svg 组件
react-native-syan-image-picker
图片选择、拍照组件, 因为 react-native-file-selector 中引用的 FileBrowser 有问题,暂时弃用
axios
通信组件,RN 官方推荐的 Fetch 不支持拦截器
rn-fetch-blob
网络传输文件
jpush jshare jcore
极光推送,极光分享, 有相对详细的 react-native 集成文档
teaset
国人写的 UI 组件
react-native-wechat
微信登录、支付、分享
react-native-audio
播放音频文件
react-native-video
播放视频文件
react-native-sound
控制音量
react-native-orientaion
控制屏幕方向
react-native-image-zoom-viewer
点击图片预览、放大、手势关闭
lottie-react-native
播放 AE 动效
难点
ios
CocoaPods 的仓库国内很难访问到,可以用先下载到本地的方式完成配置
android
在 android/gradle.properties 文件中配置如下内容
1 | # 使用代理 |
总之做 React Native 开发需要十分稳定的\$\$代理
使用 CocoaPods 的项目需要在 ios 目录下执行 pod install 安装全部依赖
然后打开.xcworkspace 文件编译
android 打包需要下载对应版本的 gradle 和 jar 包,强烈依赖翻墙
AppGlideModule 问题
在 build.gradle 中加入下面代码
1 | project.ext { |
字体安装
将字体放到 app/src/main/assets/fonts 目录下
编辑 Info.plist 加入下列内容
1 | <key>NSLocationWhenInUseUsageDescription</key> |
编辑 app/src/main/AndroidManifest.xml
1 | <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
需要深入理解
TouchableOpacity 在安卓下没有 onPress 事件,因为要引用 react-native 中的同名类,自动引用总是引错
Xcode 选择 TARGETS 项目,General 下的 Deployment Info 下的 DeviceOrientation 只勾选 Portrait
AndroidManifest.xml 中为 MainActivity 添加 android:screenOrientation=”portrait”
很多开源项目都带有 example 目录方便查看效果,但因为 react-native 版本更新迭代相当快,如果不满足当前 react-native 版本的基本无法运行
react-native 更新非常快,应保持项目依赖的 react-native 大版本稳定在半年至一年更新,包括 android 和 ios 项目格式的更新
班车 APP 乘客
1 | # 安装依赖包 |
1 | # 可以清除修改了js构建方案后之前的顽固缓存 |
集成后安卓闪退问题,需要配置 res 下的 xml 文件
1 | signingConfigs { |
1 | # 生成keystore |
版本 1.9.12
因为 ReactNative0.59 已经支持自动 link 不需要进行手动链结动态库进来
其他步骤照旧
因为自动 link,不需要编辑 1、2 步
The modules [‘node_modules-react-native-wechat-lib-android-RCTWeChat’, ‘node_modules-react-native-wechat-lib-android-react-native-wechat-lib~1’] point to the same directory in the file system.
Each module must have a unique path.不要配置上面的 1、2 步
安卓打包提示 WeChatModule.java:7: 错误: 程序包 android.support.annotation 不存在 进入 WeChatModule 包修改文件
1 | //import android.support.annotation.Nullable; |
jcore-react-native 1.7.5
jpush-react-native 2.7.5
按文档完全可配置,如何调用需测试
xcode 要将 icommon.ttf 拖拽到项目根路径, 在 info.plist 中添加 Fonts provided by application > icomoon.ttf
方法 1: 高阶组件套壳
通过高阶组件在外部定义弹窗组件通过 redux state 触发渲染
优点:稳定
缺点:state 变更后会触发大面积的高阶组件重绘
方法 2: 使用 react-native-root-siblings
优点:快,直接提供了插入到根路径的功能,方便编写
缺点:hack 了 AppRegistry.registerComponent 方法,不知道新版本绘有何问题。所有组件需做好退回 hoc 编写的方案上
我选择快[Doge]
当前版本:1.0.0-alpha.7
ios 目录下 pod install
在 android/settings.gradle 添加代码
1 | include ':aliyun-oss-react-native' |
在 android/app/build.gradle 里增加代码
1 | dependencies { |
在 AndroidManifest.xml 中添加
1 | <manifest |
./gradlew assembleRelease 失败 #49
Execution failed for task ‘:aliyun-oss-react-native:verifyReleaseResources’.
修改
1 | xmlns:tools="http://schemas.android.com/tools"> |
修改 node_modules/aliyun-oss-react-native/android/build.gradle
1 | android { |
lottie 中带图片的需要在安卓对应目录下拷贝资源文件到[PROJECT FOLDER]/android/app/src/main/assets,在 react prop 中对应其子目录 imageAssetsFolder={‘lottie/animation_1’}
在 Xcode 中左侧文件夹右键 “Add file to [Project]” 将文件添加进去重新编译即可
文件名需和 json 中的文件一致
安卓虚拟机堆栈爆满问题
Expiring Daemon because JVM heap space is exhausted
在 android/app/build.gradle 中添加
1 | android { |
在 android/gradle.properties 中添加
1 | org.gradle.daemon=true |
adb logcat AndroidRuntime:E *:S
手机插上线,打开 Android Studio logcat 面板 过滤 I/ReactNativeJS 级别 debug
启动图标
安卓启动图(内容尽量靠中间)
2560*1440
安卓图标
圆形,圆角
192x192
144x144
96x96
72x72
48x48
ios
这个问题是因为升级了新的编译器,之前已经用旧编译器生成过结果需要进入/Users/\${username}/Library/Developer/Xcode/DerivedData 将数据清除
也可以清除 Pods/目录,重新 pod install 一下
2019 年底我从工作了 6 年的公司离职了。原因嘛,内耗严重,没有升职空间。最关键的是技术负责人为了“降低成本”选了 LayUI 作为后端框架,完全背离整个技术行业的发展方向,这个没法忍。很多人可能没法接受我在新公司成立会上的举动,然而这就是我,我无法选择沉默,抛开利益谈理想都是耍流氓。强烈的个性促成了我选择前端工作,6 年里为这家公司构建了 3 套完整的后端框架,一套移动端组件库,高度可配置营销方案,完整的前端开发部署流程,甚至到广州拿项目的高并发架构,开发项目无数。我早已做到问心无愧。
后面去了一家以前老大负责的公司,中恒天汽车集团下属的越野部落。在西二旗。路挺远的,每天单程 2 小时。真不知那阵是怎么熬过来的,也许是一股热情维持的吧。去了那家公司薪资很好,职位前端架构师,带一个不错的小伙子做个 RN 项目。因为一直以来都为了上家公司利益服务,手机客户端这块算是个空白。心里一股劲就想搞一个东西出来,这回是真的用心做了。然而。。。
转过年遇上了新冠疫情,这段时间到复工一直在家开发。RN 新手的我克服了各种困难搭起了项目架构顺利开发,个中的心酸只有打碎牙往肚里咽了。一晃时间就来到了 4 月,App 再做一期就可以上线了,然而整个集团却开始不稳定起来,不发工资了。
3 月份的工资拖到了五一发,4 月的拖到了我离职才发。起初以为只是简单的疫情原因,后来才知道江湖上水有多深、有多混,我真是太单纯了。就这样我的 App 梦想以一种闹剧收场,黯然辞职。不过在这里我还是得感谢这位给我两次机会的领导,你是我人生路上的贵人,你在我心中的形象一直十分高大。
6 月收到了 FESCO 的 offer,自降 10k 工资,也是架构师。然而这也不踏实,一进来就大量的人员离职,直接背了前任们留下的各种锅,填了 3 个多月的坑。每天都在背锅填坑,忙忙碌碌的过了 3 个月。好在项目已经到了中后期,已经没有太多新需求。
如今的我已经到了 IT 民工的末期,不知道未来如何,只有过好每一天了。先定个小目标,搬砖到 40 岁。
docker stack 需要在编写完 docker-compose(会读取Compose配置文件) 和创建好 docker swarm(使用Node Worker) 后使用
开启stack,更新stack
别名
docker stack up
部署docker-compose编排服务
1 | docker stack deploy $stack_name -c docker-compose.yml |
停止stack,删除stack
别名
docker stack down
1 | docker stack rm $stack_name |
显示stack列表
别名
docker stack list
显示正在运行的stack列表
1 | docker stack ps |
显示stack中的服务
1 | docker stack services $stack_name |
1 | docker-compose ps | tail -n +3 | awk '{print $1}' | xargs -n1 docker logs |
至此,我们已经完成了从编写Dockerfile跑webapp,再到编写docker-compose跑整个服务,再到集群化部署服务的过程。
写的比较简单,还需要遇到真实场景去做更复杂的处理
直接来到了k8s,为什么直接写k8s呢?因为简单啊!
我一个前端看tm什么k8s呢。本着探索的精神我只想在自己机器上跑起来而已。在这里只探索跑起来,因为跑起来已经很tm难啦。你还想玩的溜,多努力吧少年!
因为google的原因?所有k8s的资源都是被墙的,即便是挂着小飞机也不行。网上搜到的所有方案全部无效。直到我找到了github上一个仓库k8s-for-docker-desktop,解决了问题。
注:上面的方法只是解决Docker Desktop的Kubernetes,linux下的应该大致相同但又有不同
好吧,照着做就行了😊
docker swarm 是 docker亲生的管理docker集群的工具。kubernetes是google私生的,不过现在已经转正。
swarm是一个运行docker engine节点(node)的集合,每台跑着docker的机器都可以被视为一个节点。这个节点集合可以用来发布和编排服务。
节点可以主动初始化一个swarm或者加入一个已经存在的swarm。这样该节点就成为了swarm中的一个节点。
swarm中的节点分为2种角色
manager节点用于cluster的管理,swarm命令基本只能在manager节点执行。一个cluster可以有多个manager节点,但只有一个节点可以成为leader manager node,leader选主通过raft协议实现,参数可配置。
worker节点是任务执行节点,manager将service下发至worker节点执行。
STATUS为空的是worker节点,Reachable的是非leader manager node。Manager节点默认也作为worker节点。
1 | # 处于 |
1 | docker swarm init --listen-addr ip:port --advertise-addr ip |
创建集群的节点,自己就是manager了。会返回加入worker所需的token
1 | docker swarm join-token manager |
在其他节点上执行上面获取的命令即可
1 | docker swarm leave --force |
已经跑起服务的需要强制退出
Task是swarm中的最小原子调度单位,就是一个单一的容器
Service 是一组Task的集合,Service 定义 Task的属性
Service 有两种模式:
replicated service: 按一定规则在各节点上运行指定个数的Task
global service:每个节点上只运行一个task
因为有docker stack 绝大部分指令了解即可
1 | docker service create --replicas 2 --name helloworld --network=swarm_test nginx:alpine |
1 | docker service ls |
1 | docker service ps helloworld |
1 | docker service scale helloworld=3 |
可扩大,也可缩小
有点像一种神秘的柱状物(金箍棒)可大可小
1 | docker service rollback $service_id |
1 | docker service update $service_id |
1 | docker service inspect $service_id |
使用方法
1 | docker service logs $service_id |
等价于
1 | docker logs $container_id |
1 | docker node ls |
1 | docker network ls |
docker swarm得网络配置是十分丰富的,而且自带服务发现功能
基于swarm搭配负载均衡工具这些实践还没有做
To Be Continue
我曾经跨过山河大海、也穿过人山人海!!看过了前面那么多知识概念,自己的docker镜像终于跑起来了。但总感觉少了点什么,那就是老敲命令太tm烦了。尤其是container每次还的先删掉才能重新启动。docker run
那么多参数哥真的记不住啊。一个项目要依赖很多服务,又要部署超多实例,没有带给我们丝毫的便利。于是有人来拯救我们了!
使用docker-compose可以轻松、高效的管理容器,它是一个定义和运行多容器Docker应用的工具。使用YAML文件来配置应用服务,只需要一行命令就可以创建运行配置的服务。
docker-compose主要围绕compose文件定义工作,从发布到目前一共有下面这些版本
Compose文件版本 | Docker Engine版本需求 |
---|---|
3.7 | 18.06.0+ |
3.6 | 18.02.0+ |
3.5 | 17.12.0+ |
3.4 | 17.09.0+ |
3.3 | 17.06.0+ |
3.2 | 17.04.0+ |
3.1 | 1.13.1+ |
3.0 | 1.13.0+ |
2.4 | 17.12.0+ |
2.3 | 17.06.0+ |
2.2 | 1.13.0+ |
2.1 | 1.12.0+ |
2.0 | 1.10.0+ |
1.0 | 1.9.1.+ |
不同版本的Compose文件格式要求不同的Docker Engine和docker-compose版本。之前就发生过Compose文件版本过高,docker-compose版本过低无法运行的窘境
可以使用最新的。也可以按阿里云一类的要求用对应版本的格式
Compose文件使用YAML
格式编写,这个格式在python,ruby等语言中比较流行
让我们来看看大搜车easy-mock服务的Compose
文件
1 | # 声明版本 |
1 | version: '3' |
假设有文件 dev.sh
1 | export NODE_RUN=dev |
在配置文件中${variable_name}引用
1 | version: '3' |
使用方法
1 | source dev.sh |
创建启动container
1 | docker-compose -f docker-compose.yml up -d --build |
停止并删除container,networks,images,volumes
1 | docker-compose -f "docker-compose.yml" down |
1 | docker-compose run web env |
单独的docker-compose只用于开发测试
配合 docker swarm 和 docker stack就是用于部署
command 和 entrypoint 最后必须能产生一个不退出进程的PID
command 和 entrypoint 指令会替换镜像 Dockerfile 中最后的 CMD 或 ENTRYPOINT 如果不太熟悉官方镜像尽量只传参数不要自己写命令
1 | command: |
1 | services: |
To Be Continue
Dockerfile是用于构建Docker镜像的配置文件。在Dockerfile中包含了一些列构建镜像需要执行的命令操作。利用Docker镜像体积小的特点能够快速实现迁移部署。
Dockerfile就是一个名为Dockerfile的文件。
Dockerfile有自己的语法,但十分简单,只有2种:指令和注释
1 | INSTRUCTION arguments |
使用FROM指定一个基础镜像
这个指令一般都出现在Dockerfile的第一行,接下来的所有工作都是基于FROM
指令指定的镜像开展的。一个合法的Dockerfile必须以FROM
指令开头。
ARG
指令允许在FROM
之前出现FROM
可以在单个Dockerfile中出现多次用来构建多个镜像或作为其他镜像的依赖。提交(commit
)之前指令构建的镜像(image
)获取ID,之后的FROM
会清除前面指令的状态FROM
指令可以选择性的添加AS name
参数来给予当前构建状态命名。命名可以被之后的FROM
和COPY --from=<name|index>
指令引用当前阶段的镜像(image
)tag
和digest
是可选的,如果忽略它们,构造器会默认添加latest
标签。若没有找到tag会报错1 | FROM <image> [AS <name>] |
1 | WORKDIR /path/to/workdir |
WORKDIR
指令设置工作目录。如果目录不存在则会创建。RUN
, CMD
, ENTRYPOINT
, COPY
, ADD
都会受到影响
RUN
指令用来执行shell命令,并且在当前镜像的最高层级上新创建一层并记录下来
RUN
有2中格式,但我个人只使用第一种
第二种方式会被解析成JSON数组,所以里面的命令必须用双引号包裹
1 | RUN <command> |
RUN
默认使用/bin/sh
shell执行命令
使用bash,当然有的极简镜像不包含bash…
1 | RUN /bin/bash -c 'echo hello' |
如果你的命令过长不易读可以使用换行符\
来多行编写
1 | RUN /bin/bash -c \ |
通常不会一次只执行一条命令而是多条可以用;
来分割
1 | RUN npm config set \ |
ENV
指指令用来设置环境变量供之后的构建使用
1 | ENV <key> <value> |
ENV <key> <value>
设置一个变量,空格前的字符串设置为变量名,空格后的整个字符串设置为值,即便后面字符串中间有空格也被包含在内
ENV <key>=<value> ...
允许一次设置多个变量,可以在值中间使用空格符
使用ENV
设置环境变量会对镜像造成持久化的影响
docker run --env key=value
RUN <key>=<value> <command>
ARG
命令用来定义变量,用户可以在构建镜像时传递参数
设置一个默认值,构建时没有传递值就使用默认的
1 | FROM mysql |
ARG
定义从当前行生效,并不从Dockerfile
启动时或命令行调用时就生效
1 | FROM busybox |
1 | docker build --build-arg user=what_user . |
USER
在第二行为some_user
USER
在第四行为what_user
ENV
是对容器设置的环境变量,而ARG
是编译变量.ENV
值可覆盖ARG
值,ENV
值始终保持在镜像中
Docker团队推荐使用COPY
,😊
1 | COPY [--chown=<user>:<group>] <src>... <dest> |
COPY
把<src>
的文件和目录拷贝到<dest>
中
支持通配符选择器
1 | COPY hom* /mydir/ # 添加"hom"开头的所有文件 |
<src>
路径必须在上下文(context)之内,不能超出范围<src>
使用相对路径<dest>
可以相对路径(相对WORKDIR)和绝对路径1 | VOLUME ["/data"] |
VOLUME
指令用来声明容器中的某个目录需要映射到某个数据卷volume
通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。
要指定宿主机目录需要配合docker run -v
等命令
1 | EXPOSE <port> [<port>/<protocol>...] |
EXPOSE
指令通知容器在运行时监听指定的端口,可以明确指定是监听TCP还是UDP默认是TCP
EXPOSE
指令并不能真正的暴露端口,只是一种指示作用。真正暴露端口还要和-p
,-P
,--link
指令对应起来才可以使用
-p
1 | docker run -p 8080:80/tcp -p 8080:80/udp ... |
使用-p将容器的80端口绑定到宿主机的8080端口上,还可以分别指定方式
-P
1 | docker run -P nginx:latest |
并将容器的80端口映射到主机随机端口
--link
1 | docker run -P nginx:latest |
添加其他容器链接到这个容器,这时被链接的容器可访问这个端口
排列组合
A 既没有在Dockerfile
里Expose
,也没有run -p
启动在这个container里的服务既不能被host主机和外网访问,也不能被link的container访问,只能在此容器内部使用
B 只在Dockerfile
里Expose
了这个端口
启动在这个container里的服务不能被docker外部世界(host和其他主机)访问,但是可以通过container link,被其他link的container访问到
C 同时在Dockerfile
里Expose
,又run -p
启动的这个cotnainer既可以被docker外部世界访问,也可以被link的container访问
D 只有run -p
docker做了特殊的隐式转换,等价于情况C,既可以被外部世界访问,也可以被link的container访问到(真对这种情况,原因是docker认为,既然你都要把port open到外部世界了,等价于其他的container肯定也能访问,所以docker做了自动的Expose
下面是mysql Dockerfile
的例子
1 | ENTRYPOINT ["docker-entrypoint.sh"] |
ENTRYPOINT
更适合用在mysql,nginx这种特定软件发行包里使用。即维护者不希望用户自己执行命令而是调用自己的入口文件
所以不再讨论这一块了
CMD
指令是设置容器启动后默认执行的命令及其参数
CMD
指令在Dockerfile
中只能写一条,如果写了多条只有最后一条会生效
1 | # (exec form, 推荐使用) |
作为普通用户
CMD
是每个Dockerfile的最后一条命令,必须保证这条命令不会退出,一旦退出容器也将停止