GithubHelp home page GithubHelp logo

sgielen / picl-k3os-image-generator Goto Github PK

View Code? Open in Web Editor NEW
186.0 8.0 78.0 60 KB

Generate images for k3os compatible with various armv8/aarch64/arm64 devices

License: MIT License

Shell 90.51% Batchfile 7.05% Dockerfile 1.11% Makefile 1.33%

picl-k3os-image-generator's Introduction

⚠️ This project is archived. ⚠️
k3os itself is dead, and I have since switched to simply installing k3s on a bare Ubuntu install. Thank you to all contributors and users!

PiCl k3os image generator

This project can be used to generate images for k3os compatible with various armv8 (aarch64) devices:

  • Raspberry Pi model 3B+
  • Raspberry Pi model 4
  • Orange Pi PC 2
  • (Other devices may be compatible as well. PRs welcome! Please file an issue if you need any help with porting.)

Getting Started

  • First, make a list of devices you want to use in your k3s cluster, their hardware types and the MAC addresses of their eth0 interface. (To find the MAC, boot any supported OS, perhaps the one that comes on the included SD card if you have one, and cat /sys/class/net/eth0/address. Or, just continue with a dummy config and the initial boot will say "there is no config for MAC xx:xx:xx:xx:xx:xx", and then you know what to call it.)
  • In the config/ directory, create one configuration file for each device, named as {MAC}.yaml (e.g. dc:a6:32:aa:bb:cc.yaml). The appropriate file will be used as a config.yaml eventually.
    • You can use environment variable references in these configuration files. During execution of ./build-image.sh the references will be expanded via envsubst.
  • For Raspberry Pi devices, you can choose which firmware to use for the build by setting an env variable RASPBERRY_PI_FIRMWARE
    • If unset, the script uses a known good version (set as DEFAULT_GOOD_PI_VERSION in the script)
    • Set to latest, which instructs the script to always pull the latest version available in the raspberry pi firmware repo (e.g. export RASPBERRY_PI_FIRMWARE=latest)
    • Set to a specific version, which instructs the script to use that version (e.g. export RASPBERRY_PI_FIRMWARE="1.20200212")
  • Run ./build-image.sh <imagetype> where imagetype is raspberrypi or orangepipc2. It will check whether all dependencies are installed for creating the image, then proceeds to create the image as picl-k3os-{k3osversion}-{imagetype}.img.
    • If you have multiple images, you can also run ./build-image.sh all to build all supported image types in one go for convenience.
  • Write the image to the SD cards for each device. The SD card must be at least 1 GB.
  • Insert the SD cards into the devices, minding correct image type per device type, of course. On first boot, they will resize their root filesystems to the size of the SD card and will install their own config.yaml in the correct place based on their MAC address. After this, they will reboot.
  • On subsequent boots, k3os will run automatically with the correct per-device config.yaml.

Performing updates

When you want to simply change the config.yaml of your devices, you don't need to reprovision the SD cards. Instead, you can run sudo mount -o remount,rw /k3os/system on the running systems and make the changes to /k3os/system/config.yaml, then reboot. Make sure to keep the config.yaml up-to-date with the respective yaml in your checkout of this repository, in case you do need to provision a new image, though!

To autoupgrade to new k3os versions you may enable the k3os upgrade feature by adding this label to your config.yaml

k3os:
    labels:
        k3os.io/upgrade: latest

In case there are major changes to this repository and you want to perform a reinstall on your devices, it's easiest to create a new image and flash it onto the device. However, depending on where your cluster data is stored, this may mean you need to reapply cluster configs to your master or use a k8s backup and restore solution like velero.

Troubleshooting

If your device should be supported, but has problems coming up, attach a screen and check what happens during boot. Normally, on initial boot, you should see the Linux kernel booting, some messages appearing regarding the resizing of the root FS, then a reboot; on subsequent boots, you should see OpenRC starting, then the k3os logo and a prompt to login.

At all times, check whether your power supply is sufficient if you're having problems. Raspberry Pis and similar devices are known to experience weird issues when the power supply cannot provide sufficient power or an improper (data/no charge) cable is used. Double-check this, or try another one, even if you think the problem is unlikely to be caused by this.

If you don't see Linux kernel messages appearing at all, but the device is supported, check whether you formatted your SD card properly, or check if you can run Raspbian or Armbian on the device.

If you see Linux appearing but there is an error during resizing, something may be up with your SD card. Change the init.resizefs to include the line "exec busybox ash" before where you expect the error occurs, and run the steps manually until you find the culprit.

If resizing works but after reboot you cannot get start k3os, use the same trick: include the line "exec busybox ash" in the normal init script and try to start k3os manually. You may need to load additional kernel modules.

Anytime you think the scripts or documentation could be improved, please file an issue or a PR and we'll be happy to help.

USB 3.0 disk performance issues

In case you hit performance issues with USB 3.0 mass storage devices adding the devices to quirks.txt may help. See example

Docker

You can build this project in Docker, e.g. when you'd rather not install dependencies on your host machine or when you're building on a Mac or Windows.

If you want to build in Docker, you can build a container containing the dependencies using:

docker build . -t picl-builder:latest

Then, run the container using:

docker run -e TARGET=all -v ${PWD}:/app -v /dev:/dev --privileged picl-builder:latest

The images will be written into your local directory once the container is done.

Authors & License

The initial code was written by Dennis Brentjes and Sjors Gielen, with many contributors since then, thanks to all. Further contributions welcome!

This project is licensed under the MIT License - see the LICENSE file for details.

picl-k3os-image-generator's People

Contributors

argjolan avatar brian-provenzano avatar captainstandby avatar elmariofredo avatar nazarewk avatar neonox31 avatar ognian avatar sgielen avatar t0b3 avatar trouble-thomas avatar wurmr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

picl-k3os-image-generator's Issues

How to correctly fix init.resizefs when booting rpi from ssd

When generating the image for raspberry pi and burning it to a ssd, so that the rpi boots from the usb disk instead of the sd card
everything it needs to be changed is this line ('p1' to '1') to make the install successful.
I'm not sure how we shall fix this. One possibility is to add a third '$IMAGE_TYPE' -> raspberrypiusb but this would lead to many changes in the if's which would make the code less readable. Another would be to add a '$IMAGE_SUBTYPE'...
The most elegant way would be to somehow programmatically find out the name of the first partition of the '$ROOTDISK'...
Any ideas ?

Slow CPU performance?

Hi,
I'm trying to use k3os to host a nodejs application on RPi4 with 4GB.
I've observed that the same application, using the same docker image run on raspbian OS performs ~2-3x better in various tests. Then I've run some simple scripts to compare CPU performance between those OS:

bench.sh:

#!/bin/bash
x=1
while [ $x -le  $1 ]
do
  x=$(( $x + 1 ))
done

When run on k3os:

$ time ./bench.sh 100000

real    0m7.305s
user    0m7.204s
sys     0m0.016s

When run on raspbian:

time ./bench.sh 100000

real    0m2.672s
user    0m2.671s
sys     0m0.000s

k3os seems to perform 2.8x slower than raspbian here.
I've also run a similar test with a nodejs while loop in a container, using the same image on both machines and the results were similar - k3os version took ~2.36x more time.
To be double sure I've tested this on 2 devices, switched SD cards between them, burned new SD card with latest k3os (v0.11.1) + rpi firmware and the results were consistent.
I've also run those tests on ubuntu server and got similar, but slightly better results than with raspbian.

Maybe those benchmarks are too simplistic, but I think that >2x difference seems quite significant. How is this possible? Is k3os missing some optimizations for RPi CPU?

Broken Build script

When building on a Linux box and when doing the Docker build on Macos 12.3.1, I run into this error:

tune2fs 1.44.1 (24-Mar-2018)
Setting interval between checks to 2592000 seconds
== Initializing root... ==
== Initializing boot... ==
== Installing... ==
cp: cannot stat '/tmp/tmp.BjxnmvbH5H/brcmfmac43455*': No such file or directory

The problem seems to be this line in build-image.sh:

7z e -y deps/rpi-firmware-nonfree-master.zip -o"$BRCMTMP" "firmware-nonfree-master/brcm/*" > /dev/null

What are the last two terms supposed to be doing? If you set BRCMTMP and run the above command, you will get an empty directory. If you delete the last two terms, you get a proper extraction of the zip file to $BRCMTMP.

How was this ever working?

After upgrade of k3os to v0.9.0, boot fails with kernel panic - attempted to kill init

I was running k3os v0.6.0 built using the generator on a Raspberry Pi 3 model B.

After a k3os-upgrade-rootfs to k3os v0.9.0, boot failed with the following messages on the logs:

NAME:
   k3os - Booting to k3s so you don't have to

USAGE:
   k3os [global options] command [command options] [arguments...]

VERSION:
   v0.9.0

COMMANDS:
   rc           early phase "run commands" / "run control" 
   config, cfg  configure k3OS
   install      install k3OS
   upgrade      perform upgrades
   help, h      Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug        Turn on debug logs [$K3OS_DEBUG]
   -help, -h      show help
   --version, -v  print the version
[    2.230329] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000

[Question] Is there a way to add binaries ?

Hello @sgielen

I tried to add wireless-tools using

dl_dep wireless-tools_30~pre9-12ubuntu1_arm64.deb https://launchpadlibrarian.net/317368711/wireless-tools_30~pre9-12ubuntu1_arm64.deb
...
unpack_deb "wireless-tools_30~pre9-12ubuntu1_arm64.deb" "root"

Binaries are present in the /sbin sdcard folder but never appears from /sbin folder after booting.
I presume this is due to k3OS rootfs which erases all file system during first boot ? If yes, is there a solution to add these binaries during image creation ?

Thanks a lot

Perform an fsck of the root filesystem before booting k3os

In init.preinit, if the filesystem is still mounted read-only, we could perform an fsck to ensure integrity of the root device.

If that changes anything, we should reboot to ensure the filesystem driver doesn't get confused. Since this may trigger a reboot loop, we should print a clear message to the screen and wait for a few seconds before rebooting.

If fsck didn't change anything, the filesystem was OK and we can continue k3os boot.

If the filesystem is already mounted read-write (perhaps the kernel cmdline is incorrect?) we could try to mount it read-only, in the same way init.resizefs does, then perform the fsck like above.

k3s not running on Raspberry Pi 3B

i tried installing k3os with an image generated with the image generator on my raspberrypi 3, and k3s didnt start, I got this from running k3s check-config:


Verifying binaries in /home/rancher/.rancher/k3s/data/923c8cc79c27e6cc2f224ae559273abdd7024ad2b27c44ad00d002988331ca5f/bin:
- sha256sum: good
- links: good

System:
- /usr/sbin iptables v1.8.3 (legacy): ok
- swap: disabled
- routes: ok

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000

info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: enabled (as module)
- CONFIG_BRIDGE: enabled (as module)
- CONFIG_BRIDGE_NETFILTER: enabled (as module)
- CONFIG_NF_NAT_IPV4: missing (fail)
- CONFIG_IP_NF_FILTER: enabled (as module)
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled (as module)
- CONFIG_NETFILTER_XT_MATCH_IPVS: enabled (as module)
- CONFIG_IP_NF_NAT: enabled (as module)
- CONFIG_NF_NAT: enabled (as module)
- CONFIG_NF_NAT_NEEDED: missing (fail)
- CONFIG_POSIX_MQUEUE: enabled

Optional Features:
- CONFIG_USER_NS: enabled
- CONFIG_SECCOMP: enabled
- CONFIG_CGROUP_PIDS: enabled
- CONFIG_BLK_CGROUP: enabled
- CONFIG_BLK_DEV_THROTTLING: enabled
- CONFIG_CGROUP_PERF: enabled
- CONFIG_CGROUP_HUGETLB: missing
- CONFIG_NET_CLS_CGROUP: enabled (as module)
- CONFIG_CGROUP_NET_PRIO: enabled
- CONFIG_CFS_BANDWIDTH: enabled
- CONFIG_FAIR_GROUP_SCHED: enabled
- CONFIG_RT_GROUP_SCHED: missing
- CONFIG_IP_NF_TARGET_REDIRECT: enabled (as module)
- CONFIG_IP_SET: enabled (as module)
- CONFIG_IP_VS: enabled (as module)
- CONFIG_IP_VS_NFCT: enabled
- CONFIG_IP_VS_PROTO_TCP: enabled
- CONFIG_IP_VS_PROTO_UDP: enabled
- CONFIG_IP_VS_RR: enabled (as module)
- CONFIG_EXT4_FS: enabled
- CONFIG_EXT4_FS_POSIX_ACL: enabled
- CONFIG_EXT4_FS_SECURITY: enabled
- Network Drivers:
  - "overlay":
    - CONFIG_VXLAN: enabled (as module)
      Optional (for encrypted networks):
      - CONFIG_CRYPTO: enabled
      - CONFIG_CRYPTO_AEAD: enabled (as module)
      - CONFIG_CRYPTO_GCM: enabled (as module)
      - CONFIG_CRYPTO_SEQIV: enabled (as module)
      - CONFIG_CRYPTO_GHASH: enabled (as module)
      - CONFIG_XFRM: enabled
      - CONFIG_XFRM_USER: enabled
      - CONFIG_XFRM_ALGO: enabled
      - CONFIG_INET_ESP: enabled (as module)
      - CONFIG_INET_XFRM_MODE_TRANSPORT: missing
- Storage Drivers:
  - "overlay":
    - CONFIG_OVERLAY_FS: enabled (as module)

STATUS: 2 (fail)

KVM and Wireguard modules

Hey there,
I just put an image generated with this tool onto my Pi4.
There seems to be some discrepancy with original K3os as it supports both kvm and wireguard modules but I get errors enabling those on an actual Pi (modules not found).

Do you have a suggestion on where/what I'd have to add to get those modules?

Add dockerfile?

Have you thought of adding a dockerfile so that this can run on a Mac or even Windows?
Ognian

CNI like Cilium won't on k3os run using the official firmware pulled

The script pulls the RPI firmware from the official repo. At the time of this writing, I've pulled the RPI firmware 1.20210831

Gettig the kernel config out of this firmware, I've found out that important kernel config in order for Cilium to run are not present.

In particular, those two are missing:

CONFIG_NET_CLS_BPF
CONFIG_BPF_JIT

and these two

CONFIG_NET_SCH_INGRESS
CONFIG_CRYPTO_USER_API_HASH

are set to m.

According to Cilium docs those should have been enabled https://docs.cilium.io/en/stable/operations/system_requirements/#linux-kernel

Which is the best approach here? Bake a custom kernel or go upstream and ask if those parameters can be enabled?

It would make sense the latter since k3os officially supports Cilium.

Unable to boot newly created image

Hello, I used the docker image to create a Raspberry PI Image. Upon trying to boot, I get a Kernel panic - not syncing: Requested init /sbin/init.resizefs failed (error -2).

I checked the troubleshooting steps and thought the issue may have been with the SD Card so I tried flashing another card and have the same issue.

I am on Windows and build the image in Docker. I then used Balena etcher to write the image to the card.

I did mount the volume to try and debug /sbin/init.resizefs but that file does not appear to exist.

Here are my logs from docker run

Click to expand
Building an image for the Raspberry Pi model 3B+/4.
== Checking or downloading dependencies... ==
RASPBERRY_PI_FIRMWARE env variable was not set - defaulting to known good firmware [1.20200212]
== Making image and filesystems... ==
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
/dev/loop3: msdos partitions 1 2
mkfs.fat 4.1 (2017-01-24)
mke2fs 1.44.1 (24-Mar-2018)
Creating filesystem with 195072 4k blocks and 48768 inodes
Filesystem UUID: c2dee55b-048c-428a-857c-1cde613c7e95
Superblock backups stored on blocks:
        32768, 98304, 163840

Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

tune2fs 1.44.1 (24-Mar-2018)
Setting interval between checks to 2592000 seconds
== Initializing root... ==
== Initializing boot... ==
== Installing... ==

== picl-k3os-v0.10.0-raspberrypi.img created. ==

Issue Installing

Having an issue where the build script is failing to unpack a package in the root-resize

macOS Cataline 10.15.6
Docker Engine v19.03.13

Built the image:

docker build . -t picl-builder:latest

Ran:

docker run -e TARGET=raspberrypi -v ${PWD}:/app -v /dev:/dev --privileged picl-builder:latest

Results:

== Making image and filesystems... ==
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
sh: 1: udevadm: not found
/dev/loop5: msdos partitions 1 2
mkfs.fat 4.1 (2017-01-24)
mke2fs 1.44.1 (24-Mar-2018)
Creating filesystem with 243968 4k blocks and 61056 inodes
Filesystem UUID: b7ed84b6-cbea-4faa-8a0a-1d4515211cc8
Superblock backups stored on blocks:
	32768, 98304, 163840, 229376

Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

tune2fs 1.44.1 (24-Mar-2018)
Setting interval between checks to 2592000 seconds
== Initializing root... ==
== Initializing boot... ==
== Installing... ==
tar: ./usr/share/doc/parted/changelog.Debian.gz: Cannot utime: No such file or directory
tar: Exiting with failure status due to previous errors

https://github.com/sgielen/picl-k3os-image-generator/blob/master/build-image.sh#L336

image

Poe Hat fan support

I'm currently try to bake an image for RPI 4 with the support for the fan mounted on top of the PoE hat. Currently booting k3os gives as result that the fan does not spin hence the pi is super hot. Did anyone try that?

Question: RPi4 Netboot

Not sure if this is more related to the Image Generator or the OS itself, but I would really love to use this without an SDcard.

Can I use this image with netboot option, like Rasbian?

is image well formed ?

Hello,

i installed the image created by your script on a raspberry pi 4. I connected with ssh to my cluster and it is ok but i have several errors:

  • Cluster is not working (The connection to the server localhost:8080 was refused).
  • The file to recover the configuration (/etc/rancher/k3s/k3s.yaml) does not exist (while it exists in normal k3os image).

Is something missing in your script ? :)

Thank you for your work :)

Cannot boot from USB on Raspberry Pi 4

I'm trying to boot from a usb drive on my Raspberry Pi 4. I have updated the bootloader to support USB booting and Raspian boots fine. When I try to boot this image though, I get the following errors:

recovery4.elf: not found (6)
recovery4.elf: not found (6)

Read start4.elf bytes 2784800
Read fixup4.elf bytes      6200
0x00c03111 0x00000000 0x00000007
start4.elf is not compatible. 
USB-MSD boot requires newer software.

I tried applying the changes from #27 but I don't think they are related to this.

I'm building using RASPBERRY_PI_FIRMWARE=latest. I also tried deleting everything in deps to make sure I was getting the latest of everything.

I also updated build-image.sh to get the latest rootfs image.

dl_dep k3os-rootfs-arm64.tar.gz https://github.com/rancher/k3os/releases/download/v0.11.1/k3os-rootfs-arm64.tar.gz

Feature Request: Wireless support

Tested on Raspberry Pi 3 B+ - The wifi parameter does not work. The wireless interface is not detected by the OS.

I'm not really sure if this is an issue with the image build (Not including drivers or something) Or a k3os issue all together.

Upgrade k3os

Hello !

Thank you for your work, you made an awesome work. I have never suceeded to install native k3os image on my raspberry 4 (and according to this link rancher/k3os#111 i am not alone) but with your project it works (and ssh config is good, it it what i was looking for !).

I would like to ask, how can i upgrade k3os version ? I tried to replace 0.6.0 by v0.9.0-rc5 which is the lastest release but i get a kernel panic.

Can you upgrade or explain how you do it (if is is understandable :p)

Thank you,
Regards :)

Wireless interface not detected on Raspberry Pi 3 B+

Hello and first thanks for this nice image builder 👍

I was able to build a k3os image for my rpi 3B+ but the wifi doesn't seem to be working.
I have seen an existing closed issue about that here : #1

The dmesg command results with :

[    6.941635] brcmfmac: F1 signature read @0x18000000=0x15264345
[    6.954731] brcmfmac: brcmf_fw_alloc_request: using brcm/brcmfmac43455-sdio for chip BCM4345/6
[    6.955326] brcmfmac mmc1:0001:1: Direct firmware load for brcm/brcmfmac43455-sdio.bin failed with error -2

First, I thought thath the problem was linked to k3os, but apparently K3OS is just an overlay on top on kernel/firmware as it said here : rancher/k3os#345 (comment)

It appears that broadcom firmware files are missing, I tried to update https://github.com/sgielen/picl-k3os-image-generator/blob/master/build-image.sh#L78 with last 1.20200212 rpi firmware but with no more luck.

@sgielen can you please help me to fix the probelm ?

Thanks

docker image no longer available

This is strange as it worked for me 2 weeks ago.

$ docker pull picl-builder:latest
> Error response from daemon: pull access denied for picl-builder,
> repository does not exist or may require 'docker login': denied: requested access to the resource is denied

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.