mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
87da80adaf
@ -1,15 +1,13 @@
|
||||
加密:如何保护 Ubuntu 16.04 上的 NGINX Web 服务器
|
||||
如何保护 Ubuntu 16.04 上的 NGINX Web 服务器
|
||||
============================================================
|
||||
|
||||
由 [Giuseppe Molica][1] 提供
|
||||
|
||||
[![Let's Encrypt Encryption CA](https://www.unixmen.com/wp-content/uploads/2017/06/le-logo-standard.png "le-logo-standard")][2]
|
||||
![Let's Encrypt Encryption CA](https://www.unixmen.com/wp-content/uploads/2017/06/le-logo-standard.png "le-logo-standard")
|
||||
|
||||
### 什么是 Let’s Encrypt
|
||||
|
||||
[Let’s Encrypt][3]是互联网安全研究组织 (ISRG) 提供的免费认证机构。它提供了一种轻松自动的方式来获取免费的 SSL/TLS 证书 - 这是在 Web 服务器上启用加密和 HTTPS 流量的必要步骤。获取和安装证书的大多数步骤可以通过使用名为 [Certbot][4] 的工具进行自动化。
|
||||
[Let’s Encrypt][3] 是互联网安全研究组织 (ISRG) 提供的免费证书认证机构。它提供了一种轻松自动的方式来获取免费的 SSL/TLS 证书 - 这是在 Web 服务器上启用加密和 HTTPS 流量的必要步骤。获取和安装证书的大多数步骤可以通过使用名为 [Certbot][4] 的工具进行自动化。
|
||||
|
||||
特别地,该软件可在可以使用 shell 的服务器上使用:换句话说,当可以通过 SSH 连接使用。
|
||||
特别地,该软件可在可以使用 shell 的服务器上使用:换句话说,它可以通过 SSH 连接使用。
|
||||
|
||||
在本教程中,我们将看到如何使用 `certbot` 获取免费的 SSL 证书,并在 Ubuntu 16.04 服务器上使用 Nginx。
|
||||
|
||||
@ -17,7 +15,7 @@
|
||||
|
||||
第一步是安装 `certbot`,该软件客户端可以几乎自动化所有的过程。 Certbot 开发人员维护自己的 Ubuntu 仓库,其中包含比 Ubuntu 仓库中存在的软件更新的软件。
|
||||
|
||||
添加Certbot 仓库:
|
||||
添加 Certbot 仓库:
|
||||
|
||||
```
|
||||
# add-apt-repository ppa:certbot/certbot
|
||||
@ -39,21 +37,21 @@ Certbot 现已安装并可使用。
|
||||
|
||||
### 获得证书
|
||||
|
||||
有各种 Certbot 插件可用于获取 SSL 证书。这些插件有助于获取证书,而其安装和 Web 服务器配置都留给管理员。
|
||||
有各种 Certbot 插件可用于获取 SSL 证书。这些插件有助于获取证书,而证书的安装和 Web 服务器配置都留给管理员。
|
||||
|
||||
我们使用一个名为 **Webroot** 的插件来获取 SSL 证书。
|
||||
|
||||
在有能力修改正在运行的内容的情况下,建议使用此插件。在证书颁发过程中不需要停止 Web 服务器。
|
||||
在有能力修改正在提供的内容的情况下,建议使用此插件。在证书颁发过程中不需要停止 Web 服务器。
|
||||
|
||||
#### 配置 NGINX
|
||||
|
||||
Webroot 通过为名为 `.well-known` 的目录中的每个域创建一个临时文件,并放置在 Web 根目录下。在我们的例子中,Web 根目录是 `/var/www/html`。确保该目录对 Let’s Encrypt 可访问以用于验证 。为此,请编辑 NGINX 配置。使用文本编辑器打开 `/etc/nginx/sites-available/default`:
|
||||
Webroot 会在 Web 根目录下的 `.well-known` 目录中为每个域创建一个临时文件。在我们的例子中,Web 根目录是 `/var/www/html`。确保该目录在 Let’s Encrypt 验证时可访问。为此,请编辑 NGINX 配置。使用文本编辑器打开 `/etc/nginx/sites-available/default`:
|
||||
|
||||
```
|
||||
# $EDITOR /etc/nginx/sites-available/default
|
||||
```
|
||||
|
||||
在该文件中,在服务器块内,输入以下内容:
|
||||
在该文件中,在 `server` 块内,输入以下内容:
|
||||
|
||||
```
|
||||
location ~ /.well-known {
|
||||
@ -67,7 +65,7 @@ Webroot 通过为名为 `.well-known` 的目录中的每个域创建一个临时
|
||||
# nginx -t
|
||||
```
|
||||
|
||||
没有错误应该会显示:
|
||||
没有错误的话应该会显示如下:
|
||||
|
||||
```
|
||||
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
||||
@ -82,29 +80,26 @@ nginx: configuration file /etc/nginx/nginx.conf test is successful
|
||||
|
||||
#### 使用 Certbot 获取证书
|
||||
|
||||
下一步是使用 Certbot 的 Webroot 插件获取新证书。在本教程中,我们将示例保护域 www.example.com。需要指定应由证书保护的每个域。执行以下命令:
|
||||
下一步是使用 Certbot 的 Webroot 插件获取新证书。在本教程中,我们将保护示例域 www.example.com。需要指定应由证书保护的每个域。执行以下命令:
|
||||
|
||||
```
|
||||
# certbot certonly --webroot --webroot-path=/var/www/html -d www.example.com
|
||||
```
|
||||
|
||||
在此过程中,Cerbot 将要求有效的电子邮件地址进行通知。还会要求与 EFF 分享,但这不是必需的。在同意服务条款之后,它将获得一个新的证书。
|
||||
在此过程中,Cerbot 将询问有效的电子邮件地址,用于进行通知。还会要求与 EFF 分享,但这不是必需的。在同意服务条款之后,它将获得一个新的证书。
|
||||
|
||||
最后,目录 `/etc/letsencrypt/archive` 将包含以下文件:
|
||||
|
||||
* chain.pem:加密链证书。
|
||||
* `chain.pem`:Let’s Encrypt 加密链证书。
|
||||
* `cert.pem`:域名证书。
|
||||
* `fullchain.pem`:`cert.pem`和 `chain.pem` 的组合。
|
||||
* `privkey.pem`:证书的私钥。
|
||||
|
||||
* cert.pem:域名证书。
|
||||
|
||||
* fullchain.pem:`cert.pem`和 `chain.pem` 的组合。
|
||||
|
||||
* privkey.pem:证书私钥。
|
||||
|
||||
Certbot 还将创建符号链接到 `/etc/letsencrypt/live/**domain_name**/` 中的最新证书文件。这是我们将在服务器配置中使用的路径。
|
||||
Certbot 还将创建符号链接到 `/etc/letsencrypt/live/domain_name/` 中的最新证书文件。这是我们将在服务器配置中使用的路径。
|
||||
|
||||
### 在 NGINX 上配置 SSL/TLS
|
||||
|
||||
下一步是服务器配置。在 `/etc/nginx/snippets/` 中创建一个新的代码段。 **snippet** 是配置文件的一部分,可以包含在虚拟主机配置文件中。所以,创建一个新的文件:
|
||||
下一步是服务器配置。在 `/etc/nginx/snippets/` 中创建一个新的代码段。 **snippet** 是指一段配置,可以包含在虚拟主机配置文件中。如下创建一个新的文件:
|
||||
|
||||
```
|
||||
# $EDITOR /etc/nginx/snippets/secure-example.conf
|
||||
@ -147,7 +142,7 @@ server {
|
||||
...
|
||||
```
|
||||
|
||||
这将启用 NGINX 加密。
|
||||
这将启用 NGINX 加密功能。
|
||||
|
||||
保存、退出并检查 NGINX 配置文件:
|
||||
|
||||
@ -166,15 +161,15 @@ nginx: configuration file /etc/nginx/nginx.conf test is successful
|
||||
|
||||
### 总结
|
||||
|
||||
按照上述步骤,此时我们已经拥有了一个安全的基于 NGINX 的 Web 服务器,它由 Certbot 和 Let’s Encrypt 加密。这只是一个基本配置,当然你可以使用许多 NGINX 配置参数来个性化所有东西,但这取决于特定的 Web 服务器要求。
|
||||
按照上述步骤,此时我们已经拥有了一个安全的基于 NGINX 的 Web 服务器,它由 Certbot 和 Let’s Encrypt 提供加密。这只是一个基本配置,当然你可以使用许多 NGINX 配置参数来个性化所有东西,但这取决于特定的 Web 服务器要求。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.unixmen.com/encryption-secure-nginx-web-server-ubuntu-16-04/
|
||||
|
||||
作者:[Giuseppe Molica ][a]
|
||||
作者:[Giuseppe Molica][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
### 我要成为一名系统管理员吗?
|
||||
|
||||
有人要你,但是你要做系统管理工作吗?如果你生活在一个第一世界国家,每季度 70,000 美元的收入看上去是一个可以感到幸福的标准收入,或者说至少减少了大部分的与钱相关的压力。系统和网络管理员的中位季度收入是 80,000 美元,很容易达标,尽管明显有些人赚的更少或更多。
|
||||
有人要你,但是你要做系统管理工作吗?如果你生活在一个第一世界国家,每年 70,000 美元的收入看上去是一个可以感到幸福的标准收入,或者说至少减少了大部分的与钱相关的压力。系统和网络管理员的中位年度收入是 80,000 美元,很容易达标,尽管明显有些人赚的更少或更多。
|
||||
|
||||
你曾经免费做过一些系统管理工作吗?我们大多数人都多多少少地管理一些设备,但是那并不代表你喜欢管理它。如果你曾经在你家的网络中添加了一些服务器,你就是一个备选的系统管理员。你想要为自己的孩子添加一个“我的世界”的游戏服务器么,所以你用树莓派搭建了一个?也许是时候来考虑通过做这样的工作来获取报酬了。
|
||||
|
||||
|
@ -0,0 +1,144 @@
|
||||
The Children's Illustrated Guide to Kubernetes
|
||||
============================================================
|
||||
|
||||
|
||||
Introducing Phippy, an intrepid little PHP app, and her journey to Kubernetes.
|
||||
|
||||
What is this? Well, I wrote a book that explains Kubernetes. We posted [a video version][1] to the Kubernetes community blog. If you find us at a conference, you stand a chance to pick up a physical copy. But for now, here's a blog post version!
|
||||
|
||||
And after you've finished reading, tweet something at [@opendeis][2] for a chance to win a squishy little Phippy toy of your own. Not sure what to tweet? Why don't you tell us about yourself and how you use Kubernetes!
|
||||
|
||||
### The Other Day...
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-1.png)
|
||||
|
||||
The other day, my daughter sidled into my office, and asked me, "Dearest Father, whose knowledge is incomparable, what is Kubernetes?"
|
||||
|
||||
Alright, that's a little bit of a paraphrase, but you get the idea.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-1.png)
|
||||
|
||||
And I responded, "Kubernetes is an open source orchestration system for Docker containers. It handles scheduling onto nodes in a compute cluster and actively manages workloads to ensure that their state matches the users' declared intentions. Using the concepts of "labels" and "pods", it groups the container which make up an application into logical units for easy management and discovery."
|
||||
|
||||
And my daughter said to me, "Huh?"
|
||||
|
||||
And so I give you...
|
||||
|
||||
### The Children's Illustrated Guide to Kubernetes
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-2.png)
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-3.png)
|
||||
|
||||
Once upon a time there was an app named Phippy. And she was a simple app. She was written in PHP and had just one page. She lived on a hosting provider and she shared her environment with scary other apps that she didn't know and didn't care to associate with. She wished she had her own environment: just her and a webserver she could call home.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-2.png)
|
||||
|
||||
An app has an environment that it relies upon to run. For a PHP app, that environment might include a webserver, a readable file system, and the PHP engine itself.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-4.png)
|
||||
|
||||
One day, a kindly whale came along. He suggested that little Phippy might be happier living in a container. And so the app moved. And the container was nice, but… It was a little bit like having a fancy living room floating in the middle of the ocean.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-3.png)
|
||||
|
||||
A container provides an isolated environment in which an app, together with its environment, can run. But those isolated containers often need to be managed and connected to the external world. Shared file systems, networking, scheduling, load balancing, and distribution are all challenges.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-5.png)
|
||||
|
||||
The whale shrugged his shoulders. "Sorry, kid," he said, and disappeared beneath the ocean's surface. But before Phippy could even begin to despair, a captain appeared on the horizon, piloting a gigantic ship. The ship was made of dozens of rafts all lashed together, but from the outside, it looked like one giant ship.
|
||||
|
||||
"Hello there, friend PHP app. My name is Captain Kube" said the wise old captain.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-4.png)
|
||||
|
||||
"Kubernetes" is the Greek word for a ship's captain. We get the words _Cybernetic_ and _Gubernatorial_ from it. Led by Google, the Kubernetes project focuses on building a robust platform for running thousands of containers in production.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-6.png)
|
||||
|
||||
"I'm Phippy," said the little app.
|
||||
|
||||
"Nice to make your acquaintance," said the Captain as he slapped a name tag on her.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-5.png)
|
||||
|
||||
Kubernetes uses labels as "nametags" to identify things. And it can query based on these labels. Labels are open-ended: You can use them to indicate roles, stability, or other important attributes.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-7.png)
|
||||
|
||||
Captain Kube suggested that the app might like to move her container to a pod on board the ship. Phippy happily moved her container inside of the pod aboard Kube's giant ship. It felt like home.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-6.png)
|
||||
|
||||
In Kubernetes, a Pod represents a runnable unit of work. Usually, you will run a single container inside of a Pod. But for cases where a few containers are tightly coupled, you may opt to run more than one container inside of the same Pod. Kubernetes takes on the work of connecting your pod to the network and the rest of the Kubernetes environment.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-8.png)
|
||||
|
||||
Phippy had some unusual interests. She was really into genetics and sheep. And so she asked the captain, "What if I want to clone myself… On demand… Any number of times?"
|
||||
|
||||
"That's easy," said the captain. And he introduced her to the replication controllers.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-7.png)
|
||||
|
||||
Replication controllers provide a method for managing an arbitrary number of pods. A replication controller contains a pod template, which can be replicated any number of times. Through the replication controller, Kubernetes will manage your pods' lifecycle, including scaling up and down, rolling deployments, and monitoring.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-9.png)
|
||||
|
||||
For many days and nights the little app was happy with her pod and happy with her replicas. But only having yourself for company is not all it's cracked up to be…. even if it is N copies of yourself.
|
||||
|
||||
Captain Kube smiled benevolently, "I have just the thing."
|
||||
|
||||
No sooner had he spoken than a tunnel opened between Phippy's replication controller and the rest of the ship. With a hearty laugh, Captain Kube said, "Even when your clones come and go, this tunnel will stay here so you can discover other pods, and they can discover you!"
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-8.png)
|
||||
|
||||
A service tells the rest of the Kubernetes environment (including other pods and replication controllers) what _services_ your application provides. While pods come and go, the service IP addresses and ports remain the same. And other applications can find your service through Kurbenetes service discovery.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-10.png)
|
||||
|
||||
Thanks to the services, Phippy began to explore the rest of the ship. It wasn't long before Phippy met Goldie. And they became the best of friends. One day, Goldie did something extraordinary. She gave Phippy a present. Phippy took one look and the saddest of sad tears escaped her eye.
|
||||
|
||||
"Why are you so sad?" asked Goldie.
|
||||
|
||||
"I love the present, but I have nowhere to put it!" sniffled Phippy.
|
||||
|
||||
But Goldie knew what to do. "Why not put it in a volume?"
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-9.png)
|
||||
|
||||
A volume represents a location where containers can access and store information. For the application, the volume appears as part of the local filesystem. But volumes may be backed by local storage, Ceph, Gluster, Elastic Block Storage, and a number of other storage backends.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-11.png)
|
||||
|
||||
Phippy loved life aboard Captain Kube's ship and she enjoyed the company of her new friends (every replicated pod of Goldie was equally delightful). But as she thought back to her days on the scary hosted provider, she began to wonder if perhaps she could also have a little privacy.
|
||||
|
||||
"It sounds like what you need," said Captain Kube, "is a namespace."
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-diagram-10.png)
|
||||
|
||||
A namespace functions as a grouping mechanism inside of Kubernetes. Services, pods, replication controllers, and volumes can easily cooperate within a namespace, but the namespace provides a degree of isolation from the other parts of the cluster.
|
||||
|
||||
![](https://deis.com/images/blog-images/kubernetes-illustrated-guide-illustration-12.png)
|
||||
|
||||
Together with her new friends, Phippy sailed the seas on Captain Kube's great boat. She had many grand adventures, but most importantly, Phippy had found her home.
|
||||
|
||||
And so Phippy lived happily ever after.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
作者简介:
|
||||
|
||||
Platform Architect at Deis. Lover of wisdom, coffee, and finely crafted code.
|
||||
|
||||
via: https://deis.com/blog/2016/kubernetes-illustrated-guide/
|
||||
|
||||
作者:[Matt Butcher ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://twitter.com/@technosophos
|
||||
[1]:http://blog.kubernetes.io/2016/06/illustrated-childrens-guide-to-kubernetes.html
|
||||
[2]:https://twitter.com/opendeis
|
198
sources/tech/20170101 What is Kubernetes.md
Normal file
198
sources/tech/20170101 What is Kubernetes.md
Normal file
@ -0,0 +1,198 @@
|
||||
What is Kubernetes?
|
||||
============================================================
|
||||
|
||||
This page is an overview of Kubernetes.
|
||||
|
||||
* [Kubernetes is][6]
|
||||
|
||||
* [Why containers?][7]
|
||||
* [Why do I need Kubernetes and what can it do?][1]
|
||||
|
||||
* [How is Kubernetes a platform?][2]
|
||||
|
||||
* [What Kubernetes is not][3]
|
||||
|
||||
* [What does _Kubernetes_ mean? K8s?][4]
|
||||
|
||||
* [What’s next][8]
|
||||
|
||||
Kubernetes is an [open-source platform for automating deployment, scaling, and operations of application containers][25] across clusters of hosts, providing container-centric infrastructure.
|
||||
|
||||
With Kubernetes, you are able to quickly and efficiently respond to customer demand:
|
||||
|
||||
* Deploy your applications quickly and predictably.
|
||||
|
||||
* Scale your applications on the fly.
|
||||
|
||||
* Roll out new features seamlessly.
|
||||
|
||||
* Limit hardware usage to required resources only.
|
||||
|
||||
Our goal is to foster an ecosystem of components and tools that relieve the burden of running applications in public and private clouds.
|
||||
|
||||
#### Kubernetes is
|
||||
|
||||
* **Portable**: public, private, hybrid, multi-cloud
|
||||
|
||||
* **Extensible**: modular, pluggable, hookable, composable
|
||||
|
||||
* **Self-healing**: auto-placement, auto-restart, auto-replication, auto-scaling
|
||||
|
||||
Google started the Kubernetes project in 2014\. Kubernetes builds upon a [decade and a half of experience that Google has with running production workloads at scale][26], combined with best-of-breed ideas and practices from the community.
|
||||
|
||||
### Why containers?
|
||||
|
||||
Looking for reasons why you should be using [containers][27]?
|
||||
|
||||
![Why Containers?](https://d33wubrfki0l68.cloudfront.net/e7b766e0175f30ae37f7e0e349b87cfe2034a1ae/3e391/images/docs/why_containers.svg)
|
||||
|
||||
The _Old Way_ to deploy applications was to install the applications on a host using the operating system package manager. This had the disadvantage of entangling the applications’ executables, configuration, libraries, and lifecycles with each other and with the host OS. One could build immutable virtual-machine images in order to achieve predictable rollouts and rollbacks, but VMs are heavyweight and non-portable.
|
||||
|
||||
The _New Way_ is to deploy containers based on operating-system-level virtualization rather than hardware virtualization. These containers are isolated from each other and from the host: they have their own filesystems, they can’t see each others’ processes, and their computational resource usage can be bounded. They are easier to build than VMs, and because they are decoupled from the underlying infrastructure and from the host filesystem, they are portable across clouds and OS distributions.
|
||||
|
||||
Because containers are small and fast, one application can be packed in each container image. This one-to-one application-to-image relationship unlocks the full benefits of containers. With containers, immutable container images can be created at build/release time rather than deployment time, since each application doesn’t need to be composed with the rest of the application stack, nor married to the production infrastructure environment. Generating container images at build/release time enables a consistent environment to be carried from development into production. Similarly, containers are vastly more transparent than VMs, which facilitates monitoring and management. This is especially true when the containers’ process lifecycles are managed by the infrastructure rather than hidden by a process supervisor inside the container. Finally, with a single application per container, managing the containers becomes tantamount to managing deployment of the application.
|
||||
|
||||
Summary of container benefits:
|
||||
|
||||
* **Agile application creation and deployment**: Increased ease and efficiency of container image creation compared to VM image use.
|
||||
|
||||
* **Continuous development, integration, and deployment**: Provides for reliable and frequent container image build and deployment with quick and easy rollbacks (due to image immutability).
|
||||
|
||||
* **Dev and Ops separation of concerns**: Create application container images at build/release time rather than deployment time, thereby decoupling applications from infrastructure.
|
||||
|
||||
* **Environmental consistency across development, testing, and production**: Runs the same on a laptop as it does in the cloud.
|
||||
|
||||
* **Cloud and OS distribution portability**: Runs on Ubuntu, RHEL, CoreOS, on-prem, Google Container Engine, and anywhere else.
|
||||
|
||||
* **Application-centric management**: Raises the level of abstraction from running an OS on virtual hardware to run an application on an OS using logical resources.
|
||||
|
||||
* **Loosely coupled, distributed, elastic, liberated [micro-services][5]**: Applications are broken into smaller, independent pieces and can be deployed and managed dynamically – not a fat monolithic stack running on one big single-purpose machine.
|
||||
|
||||
* **Resource isolation**: Predictable application performance.
|
||||
|
||||
* **Resource utilization**: High efficiency and density.
|
||||
|
||||
#### Why do I need Kubernetes and what can it do?
|
||||
|
||||
At a minimum, Kubernetes can schedule and run application containers on clusters of physical or virtual machines. However, Kubernetes also allows developers to ‘cut the cord’ to physical and virtual machines, moving from a **host-centric** infrastructure to a **container-centric** infrastructure, which provides the full advantages and benefits inherent to containers. Kubernetes provides the infrastructure to build a truly **container-centric** development environment.
|
||||
|
||||
Kubernetes satisfies a number of common needs of applications running in production, such as:
|
||||
|
||||
* [Co-locating helper processes][9], facilitating composite applications and preserving the one-application-per-container model
|
||||
|
||||
* [Mounting storage systems][10]
|
||||
|
||||
* [Distributing secrets][11]
|
||||
|
||||
* [Checking application health][12]
|
||||
|
||||
* [Replicating application instances][13]
|
||||
|
||||
* [Using Horizontal Pod Autoscaling][14]
|
||||
|
||||
* [Naming and discovering][15]
|
||||
|
||||
* [Balancing loads][16]
|
||||
|
||||
* [Rolling updates][17]
|
||||
|
||||
* [Monitoring resources][18]
|
||||
|
||||
* [Accessing and ingesting logs][19]
|
||||
|
||||
* [Debugging applications][20]
|
||||
|
||||
* [Providing authentication and authorization][21]
|
||||
|
||||
This provides the simplicity of Platform as a Service (PaaS) with the flexibility of Infrastructure as a Service (IaaS), and facilitates portability across infrastructure providers.
|
||||
|
||||
#### How is Kubernetes a platform?
|
||||
|
||||
Even though Kubernetes provides a lot of functionality, there are always new scenarios that would benefit from new features. Application-specific workflows can be streamlined to accelerate developer velocity. Ad hoc orchestration that is acceptable initially often requires robust automation at scale. This is why Kubernetes was also designed to serve as a platform for building an ecosystem of components and tools to make it easier to deploy, scale, and manage applications.
|
||||
|
||||
[Labels][28] empower users to organize their resources however they please. [Annotations][29]enable users to decorate resources with custom information to facilitate their workflows and provide an easy way for management tools to checkpoint state.
|
||||
|
||||
Additionally, the [Kubernetes control plane][30] is built upon the same [APIs][31] that are available to developers and users. Users can write their own controllers, such as [schedulers][32], with [their own APIs][33] that can be targeted by a general-purpose [command-line tool][34].
|
||||
|
||||
This [design][35] has enabled a number of other systems to build atop Kubernetes.
|
||||
|
||||
#### What Kubernetes is not
|
||||
|
||||
Kubernetes is not a traditional, all-inclusive PaaS (Platform as a Service) system. It preserves user choice where it is important.
|
||||
|
||||
Kubernetes:
|
||||
|
||||
* Does not limit the types of applications supported. It does not dictate application frameworks (e.g., [Wildfly][22]), restrict the set of supported language runtimes (for example, Java, Python, Ruby), cater to only [12-factor applications][23], nor distinguish _apps_ from _services_ . Kubernetes aims to support an extremely diverse variety of workloads, including stateless, stateful, and data-processing workloads. If an application can run in a container, it should run great on Kubernetes.
|
||||
|
||||
* Does not provide middleware (e.g., message buses), data-processing frameworks (for example, Spark), databases (e.g., mysql), nor cluster storage systems (e.g., Ceph) as built-in services. Such applications run on Kubernetes.
|
||||
|
||||
* Does not have a click-to-deploy service marketplace.
|
||||
|
||||
* Does not deploy source code and does not build your application. Continuous Integration (CI) workflow is an area where different users and projects have their own requirements and preferences, so it supports layering CI workflows on Kubernetes but doesn’t dictate how layering should work.
|
||||
|
||||
* Allows users to choose their logging, monitoring, and alerting systems. (It provides some integrations as proof of concept.)
|
||||
|
||||
* Does not provide nor mandate a comprehensive application configuration language/system (for example, [jsonnet][24]).
|
||||
|
||||
* Does not provide nor adopt any comprehensive machine configuration, maintenance, management, or self-healing systems.
|
||||
|
||||
On the other hand, a number of PaaS systems run _on_ Kubernetes, such as [Openshift][36], [Deis][37], and [Eldarion][38]. You can also roll your own custom PaaS, integrate with a CI system of your choice, or use only Kubernetes by deploying your container images on Kubernetes.
|
||||
|
||||
Since Kubernetes operates at the application level rather than at the hardware level, it provides some generally applicable features common to PaaS offerings, such as deployment, scaling, load balancing, logging, and monitoring. However, Kubernetes is not monolithic, and these default solutions are optional and pluggable.
|
||||
|
||||
Additionally, Kubernetes is not a mere _orchestration system_ . In fact, it eliminates the need for orchestration. The technical definition of _orchestration_ is execution of a defined workflow: first do A, then B, then C. In contrast, Kubernetes is comprised of a set of independent, composable control processes that continuously drive the current state towards the provided desired state. It shouldn’t matter how you get from A to C. Centralized control is also not required; the approach is more akin to _choreography_ . This results in a system that is easier to use and more powerful, robust, resilient, and extensible.
|
||||
|
||||
#### What does _Kubernetes_ mean? K8s?
|
||||
|
||||
The name **Kubernetes** originates from Greek, meaning _helmsman_ or _pilot_ , and is the root of _governor_ and [cybernetic][39]. _K8s_ is an abbreviation derived by replacing the 8 letters “ubernete” with “8”.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/
|
||||
|
||||
作者:[kubernetes.io][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://kubernetes.io/
|
||||
[1]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#why-do-i-need-kubernetes-and-what-can-it-do
|
||||
[2]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#how-is-kubernetes-a-platform
|
||||
[3]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#what-kubernetes-is-not
|
||||
[4]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#what-does-kubernetes-mean-k8s
|
||||
[5]:https://martinfowler.com/articles/microservices.html
|
||||
[6]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#kubernetes-is
|
||||
[7]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#why-containers
|
||||
[8]:https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#whats-next
|
||||
[9]:https://kubernetes.io/docs/concepts/workloads/pods/pod/
|
||||
[10]:https://kubernetes.io/docs/concepts/storage/volumes/
|
||||
[11]:https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
[12]:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
|
||||
[13]:https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/
|
||||
[14]:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
|
||||
[15]:https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/
|
||||
[16]:https://kubernetes.io/docs/concepts/services-networking/service/
|
||||
[17]:https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller/
|
||||
[18]:https://kubernetes.io/docs/tasks/debug-application-cluster/resource-usage-monitoring/
|
||||
[19]:https://kubernetes.io/docs/concepts/cluster-administration/logging/
|
||||
[20]:https://kubernetes.io/docs/tasks/debug-application-cluster/debug-application-introspection/
|
||||
[21]:https://kubernetes.io/docs/admin/authorization/
|
||||
[22]:http://wildfly.org/
|
||||
[23]:https://12factor.net/
|
||||
[24]:https://github.com/google/jsonnet
|
||||
[25]:http://www.slideshare.net/BrianGrant11/wso2con-us-2015-kubernetes-a-platform-for-automating-deployment-scaling-and-operations
|
||||
[26]:https://research.google.com/pubs/pub43438.html
|
||||
[27]:https://aucouranton.com/2014/06/13/linux-containers-parallels-lxc-openvz-docker-and-more/
|
||||
[28]:https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
|
||||
[29]:https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
|
||||
[30]:https://kubernetes.io/docs/concepts/overview/components/
|
||||
[31]:https://kubernetes.io/docs/reference/api-overview/
|
||||
[32]:https://git.k8s.io/community/contributors/devel/scheduler.md
|
||||
[33]:https://git.k8s.io/community/contributors/design-proposals/extending-api.md
|
||||
[34]:https://kubernetes.io/docs/user-guide/kubectl-overview/
|
||||
[35]:https://github.com/kubernetes/community/blob/master/contributors/design-proposals/principles.md
|
||||
[36]:https://www.openshift.org/
|
||||
[37]:http://deis.io/
|
||||
[38]:http://eldarion.cloud/
|
||||
[39]:http://www.etymonline.com/index.php?term=cybernetics
|
141
sources/tech/20170102 What is Kubernetes.md
Normal file
141
sources/tech/20170102 What is Kubernetes.md
Normal file
@ -0,0 +1,141 @@
|
||||
### What is Kubernetes?
|
||||
|
||||
Kubernetes, or k8s ( _k, 8 characters, s...get it?_ ), or “kube” if you’re into brevity, is an open source platform that automates [Linux container][3] operations. It eliminates many of the manual processes involved in deploying and scaling containerized applications. In other words, you can cluster together groups of hosts running Linux containers, and Kubernetes helps you easily and efficiently manage those clusters. These clusters can span hosts across [public][4], [private][5], or hybrid clouds.
|
||||
|
||||
Kubernetes was originally developed and designed by engineers at Google. Google was one of the [early contributors to Linux container technology][6] and has talked publicly about how [everything at Google runs in containers][7]. (This is the technology behind Google’s cloud services.) Google generates more than 2 billion container deployments a week—all powered by an internal platform: [Borg][8]. Borg was the predecessor to Kubernetes and the lessons learned from developing Borg over the years became the primary influence behind much of the Kubernetes technology.
|
||||
|
||||
_Fun fact: The seven spokes in the Kubernetes logo refer to the project’s original name, “[Project Seven of Nine][1].”_
|
||||
|
||||
Red Hat was one of the first companies to work with Google on Kubernetes, even prior to launch, and has become the [2nd leading contributor][9] to Kubernetes upstream project. Google [donated][10] the Kubernetes project to the newly formed [Cloud Native Computing Foundation][11] in 2015.
|
||||
|
||||
* * *
|
||||
|
||||
### Why do you need Kubernetes?
|
||||
|
||||
Real production apps span multiple containers. Those containers must be deployed across multiple server hosts. Kubernetes gives you the orchestration and management capabilities required to deploy containers, at scale, for these workloads. Kubernetes orchestration allows you to build application services that span multiple containers, schedule those containers across a cluster, scale those containers, and manage the health of those containers over time.
|
||||
|
||||
Kubernetes also needs to integrate with networking, storage, security, telemetry and other services to provide a comprehensive container infrastructure.
|
||||
|
||||
![Kubernetes explained - diagram](https://www.redhat.com/cms/managed-files/styles/max_size/s3/kubernetes-diagram-902x416.png?itok=C_wxL4HV "Kubernetes explained - diagram")
|
||||
|
||||
Of course, this depends on how you’re using containers in your environment. A rudimentary application of Linux containers treats them as efficient, fast virtual machines. Once you scale this to a production environment and multiple applications, it's clear that you need multiple, colocated containers working together to deliver the individual services. This significantly multiplies the number of containers in your environment and as those containers accumulate, the complexity also grows.
|
||||
|
||||
Kubernetes fixes a lot of common problems with container proliferation—sorting containers together into a ”pod.” Pods add a layer of abstraction to grouped containers, which helps you schedule workloads and provide necessary services—like networking and storage—to those containers. Other parts of Kubernetes help you load balance across these pods and ensure you have the right number of containers running to support your workloads.
|
||||
|
||||
With the right implementation of Kubernetes—and with the help of other open source projects like [Atomic Registry][12], [Open vSwitch][13], [heapster][14], [OAuth][15], and [SELinux][16]— you can orchestrate all parts of your container infrastructure.
|
||||
|
||||
* * *
|
||||
|
||||
### What can you do with Kubernetes?
|
||||
|
||||
The primary advantage of using Kubernetes in your environment is that it gives you the platform to schedule and run containers on clusters of physical or virtual machines. More broadly, it helps you fully implement and rely on a container-based infrastructure in production environments. And because Kubernetes is all about automation of operational tasks, you can do many of the same things that other application platforms or management systems let you do, but for your containers.
|
||||
|
||||
With Kubernetes you can:
|
||||
|
||||
* Orchestrate containers across multiple hosts.
|
||||
|
||||
* Make better use of hardware to maximize resources needed to run your enterprise apps.
|
||||
|
||||
* Control and automate application deployments and updates.
|
||||
|
||||
* Mount and add storage to run stateful apps.
|
||||
|
||||
* Scale containerized applications and their resources on the fly.
|
||||
|
||||
* Declaratively manage services, which guarantees the deployed applications are always running how you deployed them.
|
||||
|
||||
* Health-check and self-heal your apps with autoplacement, autorestart, autoreplication, and autoscaling.
|
||||
|
||||
Kubernetes, however, relies on other projects to fully provide these orchestrated services. With the addition of other open source projects, you can fully realize the power of Kubernetes. These necessary pieces include (among others):
|
||||
|
||||
* Registry, through projects like Atomic Registry or Docker Registry.
|
||||
|
||||
* Networking, through projects like OpenvSwitch and intelligent edge routing.
|
||||
|
||||
* Telemetry, through projects such as heapster, kibana, hawkular, and elastic.
|
||||
|
||||
* Security, through projects like LDAP, SELinux, RBAC, and OAUTH with multi-tenancy layers.
|
||||
|
||||
* Automation, with the addition of Ansible playbooks for installation and cluster life-cycle management.
|
||||
|
||||
* Services, through a rich catalog of precreated content of popular app patterns.
|
||||
|
||||
[Get all of this, prebuilt and ready to deploy, with Red Hat OpenShift][17]
|
||||
|
||||
* * *
|
||||
|
||||
### Learn to speak Kubernetes
|
||||
|
||||
Like any technology, there are a lot of words specific to the technology that can be a barrier to entry. Let's break down some of the more common terms to help you understand Kubernetes.
|
||||
|
||||
**Master:** The machine that controls Kubernetes nodes. This is where all task assignments originate.
|
||||
|
||||
**Node:** These machines perform the requested, assigned tasks. The Kubernetes master controls them.
|
||||
|
||||
**Pod:** A group of one or more containers deployed to a single node. All containers in a pod share an IP address, IPC, hostname, and other resources. Pods abstract network and storage away from the underlying container. This lets you move containers around the cluster more easily.
|
||||
|
||||
**Replication controller: ** This controls how many identical copies of a pod should be running somewhere on the cluster.
|
||||
|
||||
**Service:** This decouples work definitions from the pods. Kubernetes service proxies automatically get service requests to the right pod—no matter where it moves to in the cluster or even if it’s been replaced.
|
||||
|
||||
**Kubelet:** This service runs on nodes and reads the container manifests and ensures the defined containers are started and running.
|
||||
|
||||
**kubectl:** This is the command line configuration tool for Kubernetes.
|
||||
|
||||
[Had enough? No? Check out the Kubernetes glossary.][18]
|
||||
|
||||
* * *
|
||||
|
||||
### Using Kubernetes in production
|
||||
|
||||
Kubernetes is open source. And, as such, there’s not a formalized support structure around that technology—at least not one you’d trust your business on. If you had an issue with your implementation of Kubernetes, while running in production, you’re not going to be very happy. And your customers probably won’t, either.
|
||||
|
||||
That’s where [Red Hat OpenShift][2] comes in. OpenShift is Kubernetes for the enterprise—and a lot more. OpenShift includes all of the extra pieces of technology that makes Kubernetes powerful and viable for the enterprise, including: registry, networking, telemetry, security, automation, and services. With OpenShift, your developers can make new containerized apps, host them, and deploy them in the cloud with the scalability, control, and orchestration that can turn a good idea into new business quickly and easily.
|
||||
|
||||
Best of all, OpenShift is supported and developed by the #1 leader in open source, Red Hat.
|
||||
|
||||
* * *
|
||||
|
||||
### A look at how Kubernetes fits into your infrastructure
|
||||
|
||||
![Kubernetes diagram](https://www.redhat.com/cms/managed-files/styles/max_size/s3/kubernetes-diagram-2-824x437.png?itok=KmhLmkgi "Kubernetes diagram")
|
||||
|
||||
Kubernetes runs on top of an operating system ([Red Hat Enterprise Linux Atomic Host][19], for example) and interacts with pods of containers running on the nodes. The Kubernetes master takes the commands from an administrator (or DevOps team) and relays those instructions to the subservient nodes. This handoff works with a multitude of services to automatically decide which node is best suited for the task. It then allocates resources and assigns the pods in that node to fulfill the requested work.
|
||||
|
||||
So, from an infrastructure point of view, there is little change to how you’ve been managing containers. Your control over those containers happens at a higher level, giving you better control without the need to micromanage each separate container or node. Some work is necessary, but it’s mostly a question of assigning a Kubernetes master, defining nodes, and defining pods.
|
||||
|
||||
### What about docker?
|
||||
|
||||
The [docker][20] technology still does what it's meant to do. When kubernetes schedules a pod to a node, the kubelet on that node will instruct docker to launch the specified containers. The kubelet then continuously collects the status of those containers from docker and aggregates that information in the master. Docker pulls containers onto that node and starts and stops those containers as normal. The difference is that an automated system asks docker to do those things instead of the admin doing so by hand on all nodes for all containers.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.redhat.com/en/containers/what-is-kubernetes
|
||||
|
||||
作者:[www.redhat.com ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.redhat.com/
|
||||
[1]:https://cloudplatform.googleblog.com/2016/07/from-Google-to-the-world-the-Kubernetes-origin-story.html
|
||||
[2]:https://www.redhat.com/en/technologies/cloud-computing/openshift
|
||||
[3]:https://www.redhat.com/en/containers/whats-a-linux-container
|
||||
[4]:https://www.redhat.com/en/topics/cloud-computing/what-is-public-cloud
|
||||
[5]:https://www.redhat.com/en/topics/cloud-computing/what-is-private-cloud
|
||||
[6]:https://en.wikipedia.org/wiki/Cgroups
|
||||
[7]:https://speakerdeck.com/jbeda/containers-at-scale
|
||||
[8]:http://blog.kubernetes.io/2015/04/borg-predecessor-to-kubernetes.html
|
||||
[9]:http://stackalytics.com/?project_type=kubernetes-group&metric=commits
|
||||
[10]:https://techcrunch.com/2015/07/21/as-kubernetes-hits-1-0-google-donates-technology-to-newly-formed-cloud-native-computing-foundation-with-ibm-intel-twitter-and-others/
|
||||
[11]:https://www.cncf.io/
|
||||
[12]:http://www.projectatomic.io/registry/
|
||||
[13]:http://openvswitch.org/
|
||||
[14]:https://github.com/kubernetes/heapster
|
||||
[15]:https://oauth.net/
|
||||
[16]:https://selinuxproject.org/page/Main_Page
|
||||
[17]:https://www.redhat.com/en/technologies/cloud-computing/openshift
|
||||
[18]:https://kubernetes.io/docs/reference/
|
||||
[19]:https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux/options
|
||||
[20]:https://www.redhat.com/en/containers/what-is-docker
|
@ -1,570 +0,0 @@
|
||||
translating by GitFuture
|
||||
|
||||
OpenGL & Go Tutorial Part 1: Hello, OpenGL
|
||||
============================================================
|
||||
|
||||
_[Part 1: Hello, OpenGL][6]_ | _[Part 2: Drawing the Game Board][7]_ | _[Part 3: Implementing the Game][8]_
|
||||
|
||||
_The full source code of the tutorial is available on [GitHub][9]._
|
||||
|
||||
### Introduction
|
||||
|
||||
[OpenGL][19] is pretty much the gold standard for any kind of graphics work, from desktop GUIs to games to mobile applications and even the web, I can almost guarantee you’ve viewed something rendered by OpenGL today. However, regardless of how popular and useful OpenGL is, it can be quite intimidating to get started compared to more high-level graphics libraries.
|
||||
|
||||
The purpose of this tutorial is to give you a starting point and basic understanding of OpenGL, and how to utilize it with [Go][20]. There are bindings for OpenGL in just about every language and Go is no exception with the [go-gl][21] packages, a full suite of generated OpenGL bindings for various OpenGL versions.
|
||||
|
||||
The tutorial will walk through a few phases outlined below, with our end goal being to implement [Conway’s Game of Life][22] using OpenGL to draw the game board in a desktop window. The full source code is available on GitHub at [github.com/KyleBanks/conways-gol][23] so feel free to check it out if you get stuck or use it as a reference if you decide to go your own way.
|
||||
|
||||
Before we get started, we need to get an understanding of what _Conway’s Game of Life_ actually is. Here’s the summary from [Wikipedia][24]:
|
||||
|
||||
> The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.
|
||||
>
|
||||
> The “game” is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves, or, for advanced “players”, by creating patterns with particular properties.
|
||||
>
|
||||
> Rules
|
||||
>
|
||||
> The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, alive or dead, or “populated” or “unpopulated” (the difference may seem minor, except when viewing it as an early model of human/urban behaviour simulation or how one views a blank space on a grid). Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:
|
||||
>
|
||||
> 1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
|
||||
> 2. Any live cell with two or three live neighbours lives on to the next generation.
|
||||
> 3. Any live cell with more than three live neighbours dies, as if by overpopulation.
|
||||
> 4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
|
||||
|
||||
And without further ado, here’s a demo of what we’ll be building:
|
||||
|
||||
![Conway's Game of Life in OpenGL and Golang Tutorial - Demo Game](https://kylewbanks.com/images/post/golang-opengl-conway-1.gif)
|
||||
|
||||
In our simulation, a white cell indicates that it is alive, and black cell indicates that it is not.
|
||||
|
||||
### Outline
|
||||
|
||||
The tutorial is going to cover a lot of ground starting with the basics, however it will assume you have a minimal working knowledge of Go - at the very least you should know the basics of variables, slices, functions and structs, and have a working Go environment setup. I’ve developed the tutorial using Go version 1.8, but it should be compatible with previous versions as well. There is nothing particularly novel here in the Go implementation, so if you have experience in any similar programming language you should be just fine.
|
||||
|
||||
As for the tutorial, here’s what we’ll be covering:
|
||||
|
||||
* [Part 1: Hello, OpenGL][10]: Install and Setup OpenGL and [GLFW][11], Draw a Triangle to the Window
|
||||
* [Part 2: Drawing the Game Board][12]: Make a Square out of Triangles, Draw a Grid of Squares covering the Window
|
||||
* [Part 3: Implementing the Game][13]: Implement Conway’s Game
|
||||
|
||||
The final source code is available on [GitHub][25] but each _Part_ includes a _Checkpoint_ at the bottom containing the code up until that point. If anything is ever unclear or if you feel lost, check the bottom of the post for the full source!
|
||||
|
||||
Let’s get started!
|
||||
|
||||
### Install and Setup OpenGL and GLFW
|
||||
|
||||
We’ve introduced OpenGL but in order to use it we’re going to need a window to draw on to. [GLFW][26] is a cross-platform API for OpenGL that allows us to create and reference a window, and is also provided by the [go-gl][27] suite.
|
||||
|
||||
The first thing we need to do is decide on an OpenGL version. For the purposes of this tutorial we’ll use **OpenGL v4.1** but you can use **v2.1** just fine if your system doesn’t have the latest OpenGL versions. In order to install OpenGL we’ll do the following:
|
||||
|
||||
```
|
||||
# For OpenGL 4.1
|
||||
$ go get github.com/go-gl/gl/v4.1-core/gl
|
||||
|
||||
# Or 2.1
|
||||
$ go get github.com/go-gl/gl/v2.1/gl
|
||||
```
|
||||
|
||||
Next up, let’s install GLFW:
|
||||
|
||||
```
|
||||
$ go get github.com/go-gl/glfw/v3.2/glfw
|
||||
```
|
||||
|
||||
With these two packages installed, we’re ready to get started! We’re going to start by creating **main.go** and importing the packages (and a couple others we’ll need in a moment).
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl" // OR: github.com/go-gl/gl/v2.1/gl
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
)
|
||||
```
|
||||
|
||||
Next lets define the **main** function, the purpose of which is to initialize OpenGL and GLFW and display the window:
|
||||
|
||||
```
|
||||
const (
|
||||
width = 500
|
||||
height = 500
|
||||
)
|
||||
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window := initGlfw()
|
||||
defer glfw.Terminate()
|
||||
|
||||
for !window.ShouldClose() {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// initGlfw initializes glfw and returns a Window to use.
|
||||
func initGlfw() *glfw.Window {
|
||||
if err := glfw.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
glfw.WindowHint(glfw.Resizable, glfw.False)
|
||||
glfw.WindowHint(glfw.ContextVersionMajor, 4) // OR 2
|
||||
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
||||
|
||||
window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
window.MakeContextCurrent()
|
||||
|
||||
return window
|
||||
}
|
||||
```
|
||||
|
||||
Alright let’s take a minute to walk through this and see what’s going on. First we define a couple constants, **width** and **height** - these will determine the size of the window, in pixels.
|
||||
|
||||
Next we have the **main** function. Here we instruct the **runtime** package to **LockOSThread()**, which ensures we will always execute in the same operating system thread, which is important for GLFW which must always be called from the same thread it was initialized on. Speaking of which, next we call **initGlfw** to get a window reference, and defer terminating. The window reference is then used in a for-loop where we say as long as the window should remain open, do _something_ . We’ll come back to this in a bit.
|
||||
|
||||
**initGlfw** is our next function, wherein we call **glfw.Init()** to initialize the GLFW package. After that, we define some global GLFW properties, including disabling window resizing and the properties of our OpenGL version. Next it’s time to create a **glfw.Window** which is where we’re going to do our future drawing. We simply tell it the width and height we want, as well as a title, and then call **window.MakeContextCurrent**, binding the window to our current thread. Finally, we return the window.
|
||||
|
||||
If you build and run the program now, you should see… nothing. This makes sense, because we’re not actually doing anything with the window yet.
|
||||
|
||||
Let’s fix that by defining a new function that initializes OpenGL:
|
||||
|
||||
```
|
||||
// initOpenGL initializes OpenGL and returns an intiialized program.
|
||||
func initOpenGL() uint32 {
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
prog := gl.CreateProgram()
|
||||
gl.LinkProgram(prog)
|
||||
return prog
|
||||
}
|
||||
```
|
||||
|
||||
**initOpenGL**, like our **initGlfw** function above, initializes the OpenGL library and creates a _program_ . A program gives us a reference to store shaders, which can then be used for drawing. We’ll come back to this in a bit, but for now just know that OpenGL is initialized and we have a **program** reference. We also print out the OpenGL version which can be helpful for debugging.
|
||||
|
||||
Back in **main**, let’s call this new function:
|
||||
|
||||
```
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window := initGlfw()
|
||||
defer glfw.Terminate()
|
||||
|
||||
program := initOpenGL()
|
||||
|
||||
for !window.ShouldClose() {
|
||||
draw(window, program)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You’ll notice now that we have our **program** reference, we’re calling a new **draw** function within our core window loop. Eventually this function will draw all of our cells to visualize the game state, but for now its just going to clear the window so we get a black screen:
|
||||
|
||||
```
|
||||
func draw(window *glfw.Window, program uint32) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.UseProgram(prog)
|
||||
|
||||
glfw.PollEvents()
|
||||
window.SwapBuffers()
|
||||
}
|
||||
```
|
||||
|
||||
The first thing we do is call **gl.Clear** to remove anything from the window that was drawn last frame, giving us a clean slate. Next we tell OpenGL to use our program reference, which currently does nothing. Finally, we tell GLFW to check if there were any mouse or keyboard events (which we won’t be handling in this tutorial) with the **PollEvents** function, and tell the window to **SwapBuffers**. [Buffer swapping][28] is important because GLFW (like many graphics libraries) uses double buffering, meaning everything you draw is actually drawn to an invisible canvas, and only put onto the visible canvas when you’re ready - which in this case, is indicated by calling **SwapBuffers**.
|
||||
|
||||
Alright, we’ve covered a lot here, so let’s take a moment to see the fruits of our labors. Go ahead and run the program now, and you should get to see your first visual:
|
||||
|
||||
![Conway's Game of Life in OpenGL and Golang Tutorial - First Window](https://kylewbanks.com/images/post/golang-opengl-conway-2.png)
|
||||
|
||||
Beautiful.
|
||||
|
||||
### Draw a Triangle to the Window
|
||||
|
||||
We’ve made some serious progress, even if it doesn’t look like much, but we still need to actually draw something. We’ll start by drawing a triangle, which may at first seem like it would be more difficult to draw than the squares we’re eventually going to, but you’d be mistaken for thinking so. What you may not know is that triangles are probably the easiest shapes to draw, and in fact we’ll eventually be making our squares out of triangles anyways.
|
||||
|
||||
Alright so we want to draw a triangle, but how? Well, we draw shapes by defining the vertices of the shapes and providing them to OpenGL to be drawn. Let’s first define our triangle at the top of **main.go**:
|
||||
|
||||
```
|
||||
var (
|
||||
triangle = []float32{
|
||||
0, 0.5, 0, // top
|
||||
-0.5, -0.5, 0, // left
|
||||
0.5, -0.5, 0, // right
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
This looks weird, but let’s break it down. First we have a slice of **float32**, which is the datatype we always use when providing vertices to OpenGL. The slice contains 9 values, three for each vertex of a triangle. The top line, **0, 0.5, 0**, is the top vertex represented as X, Y, and Z coordinates, the second line is the left vertex, and the third line is the right vertex. Each of these pairs of three represents the X, Y, and Z coordinates of the vertex relative to the center of the window, between **-1 and 1**. So the top point has an X of zero because its X is in the center of the window, a Y of _0.5_ meaning it will be up one quarter (because the range is -1 to 1) of the window relative to the center of the window, and a Z of zero. For our purposes because we are drawing only in two dimensions, our Z values will always be zero. Now have a look at the left and right vertices and see if you can understand why they are defined as they are - it’s okay if it isn’t immediately clear, we’re going to see it on the screen soon enough so we’ll have a perfect visualization to play with.
|
||||
|
||||
Okay, we have a triangle defined, but now we need to draw it. In order to draw it, we need what’s called a **Vertex Array Object** or **vao** which is created from a set of points (what we defined as our triangle), and can be provided to OpenGL to draw. Let’s create a function called **makeVao** that we can provide with a slice of points and have it return a pointer to an OpenGL vertex array object:
|
||||
|
||||
```
|
||||
// makeVao initializes and returns a vertex array from the points provided.
|
||||
func makeVao(points []float32) uint32 {
|
||||
var vbo uint32
|
||||
gl.GenBuffers(1, &vbo)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
|
||||
|
||||
var vao uint32
|
||||
gl.GenVertexArrays(1, &vao)
|
||||
gl.BindVertexArray(vao)
|
||||
gl.EnableVertexAttribArray(0)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
|
||||
|
||||
return vao
|
||||
}
|
||||
```
|
||||
|
||||
First we create a **Vertex Buffer Object** or **vbo** to bind our **vao** to, which is created by providing the size (**4 x len(points)**) and a pointer to the points (**gl.Ptr(points)**). You may be wondering why it’s **4 x len(points)** - why not 6 or 3 or 1078? The reason is we are using **float32** slices, and a 32-bit float has 4 bytes, so we are saying the size of the buffer, in bytes, is 4 times the number of points.
|
||||
|
||||
Now that we have a buffer, we can create the **vao** and bind it to the buffer with **gl.BindBuffer**, and finally return the **vao**. This **vao** will then be used to draw the triangle!
|
||||
|
||||
Back in **main**:
|
||||
|
||||
```
|
||||
func main() {
|
||||
...
|
||||
|
||||
vao := makeVao(triangle)
|
||||
for !window.ShouldClose() {
|
||||
draw(vao, window, program)
|
||||
}
|
||||
}
|
||||
|
||||
Here we call **makeVao** to get our **vao** reference from the **triangle** points we defined before, and pass it as a new argument to the **draw** function:
|
||||
|
||||
func draw(vao uint32, window *glfw.Window, program uint32) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.UseProgram(program)
|
||||
|
||||
gl.BindVertexArray(vao)
|
||||
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle) / 3))
|
||||
|
||||
glfw.PollEvents()
|
||||
window.SwapBuffers()
|
||||
}
|
||||
```
|
||||
|
||||
Then we bind OpenGL to our **vao** so it knows what we’re talking above when we tell it to **DrawArrays**, and tell it the length of the triangle (divided by three, one for each X, Y, Z coordinate) slice so it knows how many vertices to draw.
|
||||
|
||||
If you run the application at this point you might be expecting to see a beautiful triangle in the center of the window, but unfortunately you would be mistaken. There’s still one thing left to do, you see we’ve told OpenGL that we want to draw a triangle, but we need to tell it _how_ to draw the triangle.
|
||||
|
||||
In order to do that, we need what are called fragment and vertex shaders, which are quite advanced and beyond the scope of this tutorial (and honestly, beyond the scope of my OpenGL knowledge), however [Harold Serrano on Quora][29] gives a wonderful explanation of what they are. All we absolutely need to understand for this application is that shaders are their own mini-programs (written in [OpenGL Shader Language or GLSL][30]) that manipulate vertices to be drawn by OpenGL, and are used to (for example) determine the color of a shape.
|
||||
|
||||
We start by adding two more imports and a function called **compileShader**:
|
||||
|
||||
```
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func compileShader(source string, shaderType uint32) (uint32, error) {
|
||||
shader := gl.CreateShader(shaderType)
|
||||
|
||||
csources, free := gl.Strs(source)
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
free()
|
||||
gl.CompileShader(shader)
|
||||
|
||||
var status int32
|
||||
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
|
||||
if status == gl.FALSE {
|
||||
var logLength int32
|
||||
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
|
||||
|
||||
log := strings.Repeat("\x00", int(logLength+1))
|
||||
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
|
||||
|
||||
return 0, fmt.Errorf("failed to compile %v: %v", source, log)
|
||||
}
|
||||
|
||||
return shader, nil
|
||||
}
|
||||
```
|
||||
|
||||
The purpose of this function is to receive the shader source code as a string as well as its type, and return a pointer to the resulting compiled shader. If it fails to compile we’ll get an error returned containing the details.
|
||||
|
||||
Now let’s define the shaders and compile them from **makeProgram**. Back up in our **const** block where we define **width** and **height**:
|
||||
|
||||
```
|
||||
vertexShaderSource = `
|
||||
#version 410
|
||||
in vec3 vp;
|
||||
void main() {
|
||||
gl_Position = vec4(vp, 1.0);
|
||||
}
|
||||
` + "\x00"
|
||||
|
||||
fragmentShaderSource = `
|
||||
#version 410
|
||||
out vec4 frag_colour;
|
||||
void main() {
|
||||
frag_colour = vec4(1, 1, 1, 1);
|
||||
}
|
||||
` + "\x00"
|
||||
```
|
||||
|
||||
As you can see these are strings containing GLSL source code for two shaders, one for a _vertex shader_ and another for a _fragment shader_ . The only thing special about these strings is that they both end in a null-termination character, **\x00** - a requirement for OpenGL to be able to compile them. Make note of the **fragmentShaderSource**, this is where we define the color of our shape in RGBA format using a **vec4**. You can change the value here, which is currently **RGBA(1, 1, 1, 1)** or _white_ , to change the color of the triangle.
|
||||
|
||||
Also of note is that both programs start with **#version 410**, which you should change to **#version 120** if using OpenGL 2.1. **120** is not a typo - use **120** not **210** if you’re on OpenGL 2.1!
|
||||
|
||||
Next in **initOpenGL** we’ll compile the shaders and attach them to our **program**:
|
||||
|
||||
```
|
||||
func initOpenGL() uint32 {
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prog := gl.CreateProgram()
|
||||
gl.AttachShader(prog, vertexShader)
|
||||
gl.AttachShader(prog, fragmentShader)
|
||||
gl.LinkProgram(prog)
|
||||
return prog
|
||||
}
|
||||
```
|
||||
|
||||
Here we call our **compileShader** function with the _vertex shader_ , specifying its type as a **gl.VERTEX_SHADER**, and do the same with the _fragment shader_ but specifying its type as a **gl.FRAGMENT_SHADER**. After compiling them, we attach them to our program by calling **gl.AttachShader** with our program and each compiled shader.
|
||||
|
||||
And now we’re finally ready to see our glorious triangle! Go ahead and run, and if all is well you’ll see:
|
||||
|
||||
![Conway's Game of Life in OpenGL and Golang Tutorial - Hello, Triangle!](https://kylewbanks.com/images/post/golang-opengl-conway-3.png)
|
||||
|
||||
### Summary
|
||||
|
||||
Amazing, right! All that for a single triangle, but I promise you we’ve setup the majority of the OpenGL code that will serve us for the rest of the tutorial. I highly encourage you to take a few minutes to play with the code and see if you can move, resize, and change the color of the triangle. OpenGL can be _very_ intimidating, and it can feel at times like its difficult to understand what’s going on, but understand that this isn’t magic - it only looks like it is.
|
||||
|
||||
In the next part of the tutorial we’ll make a square out of two right-angled triangles - see if you can try and figure this part out before moving on. If not, don’t worry because we’ll be walking through the code in [Part 2][31], followed by creating a full grid of squares that will act as our game board.
|
||||
|
||||
Finally, in [Part 3][32] we continue by using the grid to implement _Conway’s Game of Life!_
|
||||
|
||||
_[Part 1: Hello, OpenGL][14]_ | _[Part 2: Drawing the Game Board][15]_ | _[Part 3: Implementing the Game][16]_
|
||||
|
||||
_The full source code of the tutorial is available on [GitHub][17]._
|
||||
|
||||
### Checkpoint
|
||||
|
||||
Here’s the contents of **main.go** at this point of the tutorial:
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl" // OR: github.com/go-gl/gl/v2.1/gl
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
)
|
||||
|
||||
const (
|
||||
width = 500
|
||||
height = 500
|
||||
|
||||
vertexShaderSource = `
|
||||
#version 410
|
||||
in vec3 vp;
|
||||
void main() {
|
||||
gl_Position = vec4(vp, 1.0);
|
||||
}
|
||||
` + "\x00"
|
||||
|
||||
fragmentShaderSource = `
|
||||
#version 410
|
||||
out vec4 frag_colour;
|
||||
void main() {
|
||||
frag_colour = vec4(1, 1, 1, 1.0);
|
||||
}
|
||||
` + "\x00"
|
||||
)
|
||||
|
||||
var (
|
||||
triangle = []float32{
|
||||
0, 0.5, 0,
|
||||
-0.5, -0.5, 0,
|
||||
0.5, -0.5, 0,
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window := initGlfw()
|
||||
defer glfw.Terminate()
|
||||
program := initOpenGL()
|
||||
|
||||
vao := makeVao(triangle)
|
||||
for !window.ShouldClose() {
|
||||
draw(vao, window, program)
|
||||
}
|
||||
}
|
||||
|
||||
func draw(vao uint32, window *glfw.Window, program uint32) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.UseProgram(program)
|
||||
|
||||
gl.BindVertexArray(vao)
|
||||
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle)/3))
|
||||
|
||||
glfw.PollEvents()
|
||||
window.SwapBuffers()
|
||||
}
|
||||
|
||||
// initGlfw initializes glfw and returns a Window to use.
|
||||
func initGlfw() *glfw.Window {
|
||||
if err := glfw.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
glfw.WindowHint(glfw.Resizable, glfw.False)
|
||||
glfw.WindowHint(glfw.ContextVersionMajor, 4)
|
||||
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
||||
|
||||
window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
window.MakeContextCurrent()
|
||||
|
||||
return window
|
||||
}
|
||||
|
||||
// initOpenGL initializes OpenGL and returns an intiialized program.
|
||||
func initOpenGL() uint32 {
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prog := gl.CreateProgram()
|
||||
gl.AttachShader(prog, vertexShader)
|
||||
gl.AttachShader(prog, fragmentShader)
|
||||
gl.LinkProgram(prog)
|
||||
return prog
|
||||
}
|
||||
|
||||
// makeVao initializes and returns a vertex array from the points provided.
|
||||
func makeVao(points []float32) uint32 {
|
||||
var vbo uint32
|
||||
gl.GenBuffers(1, &vbo)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
|
||||
|
||||
var vao uint32
|
||||
gl.GenVertexArrays(1, &vao)
|
||||
gl.BindVertexArray(vao)
|
||||
gl.EnableVertexAttribArray(0)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
|
||||
|
||||
return vao
|
||||
}
|
||||
|
||||
func compileShader(source string, shaderType uint32) (uint32, error) {
|
||||
shader := gl.CreateShader(shaderType)
|
||||
|
||||
csources, free := gl.Strs(source)
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
free()
|
||||
gl.CompileShader(shader)
|
||||
|
||||
var status int32
|
||||
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
|
||||
if status == gl.FALSE {
|
||||
var logLength int32
|
||||
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
|
||||
|
||||
log := strings.Repeat("\x00", int(logLength+1))
|
||||
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
|
||||
|
||||
return 0, fmt.Errorf("failed to compile %v: %v", source, log)
|
||||
}
|
||||
|
||||
return shader, nil
|
||||
}
|
||||
```
|
||||
Let me know if this post was helpful on Twitter [@kylewbanks][33] or down below, and follow me to keep up with future posts!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
|
||||
作者:[kylewbanks ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://twitter.com/kylewbanks
|
||||
[1]:https://kylewbanks.com/category/golang
|
||||
[2]:https://kylewbanks.com/category/opengl
|
||||
[3]:https://twitter.com/intent/tweet?text=OpenGL%20%26%20Go%20Tutorial%20Part%201%3A%20Hello%2C%20OpenGL%20https%3A%2F%2Fkylewbanks.com%2Fblog%2Ftutorial-opengl-with-golang-part-1-hello-opengl%20by%20%40kylewbanks
|
||||
[4]:mailto:?subject=Check%20Out%20%22OpenGL%20%26%20Go%20Tutorial%20Part%201%3A%20Hello%2C%20OpenGL%22&body=https%3A%2F%2Fkylewbanks.com%2Fblog%2Ftutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[5]:https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fkylewbanks.com%2Fblog%2Ftutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[6]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[7]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[8]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[9]:https://github.com/KyleBanks/conways-gol
|
||||
[10]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[11]:http://www.glfw.org/
|
||||
[12]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[13]:https://kylewbanks.com/blog/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[14]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[15]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[16]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[17]:https://github.com/KyleBanks/conways-gol
|
||||
[18]:https://twitter.com/kylewbanks
|
||||
[19]:https://www.opengl.org/
|
||||
[20]:https://golang.org/
|
||||
[21]:https://github.com/go-gl/gl
|
||||
[22]:https://en.wikipedia.org/wiki/Conway's_Game_of_Life
|
||||
[23]:https://github.com/KyleBanks/conways-gol
|
||||
[24]:https://en.wikipedia.org/wiki/Conway's_Game_of_Life
|
||||
[25]:https://github.com/KyleBanks/conways-gol
|
||||
[26]:http://www.glfw.org/
|
||||
[27]:https://github.com/go-gl/glfw
|
||||
[28]:http://www.glfw.org/docs/latest/window_guide.html#buffer_swap
|
||||
[29]:https://www.quora.com/What-is-a-vertex-shader-and-what-is-a-fragment-shader/answer/Harold-Serrano?srid=aVb
|
||||
[30]:https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/glsl_overview.php
|
||||
[31]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[32]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[33]:https://twitter.com/kylewbanks
|
@ -1,3 +1,5 @@
|
||||
translating by penghuster
|
||||
|
||||
IoT Framework for Edge Computing Gains Ground
|
||||
============================================================
|
||||
|
||||
|
@ -0,0 +1,143 @@
|
||||
> translating by rieonke
|
||||
Docker vs. Kubernetes vs. Apache Mesos: Why What You Think You Know is Probably Wrong
|
||||
============================================================
|
||||
|
||||
|
||||
There are countless articles, discussions, and lots of social chatter comparing Docker, Kubernetes, and Mesos. If you listen to the partially-informed, you’d think that the three open source projects are in a fight-to-the death for container supremacy. You’d also believe that picking one over the other is almost a religious choice; with true believers espousing their faith and burning heretics who would dare to consider an alternative.
|
||||
|
||||
That’s all bunk.
|
||||
|
||||
While all three technologies make it possible to use containers to deploy, manage, and scale applications, in reality they each solve for different things and are rooted in very different contexts. In fact, none of these three widely adopted toolchains is completely like the others.
|
||||
|
||||
Instead of comparing the overlapping features of these fast-evolving technologies, let’s revisit each project’s original mission, architectures, and how they can complement and interact with each other.
|
||||
|
||||
### Let’s start with Docker…
|
||||
|
||||
Docker Inc., today started as a Platform-as-a-Service startup named dotCloud. The dotCloud team found that managing dependencies and binaries across many applications and customers required significant effort. So they combined some of the capabilities of Linux [cgroups][1] and namespaces into a single and easy to use package so that applications can consistently run on any infrastructure. This package is [the Docker image][2], which provides the following capabilities:
|
||||
|
||||
* Packages the application and the libraries in a single package (the Docker Image), so applications can consistently be deployed across many environments;
|
||||
|
||||
* Provides Git-like semantics, such as “docker push”, “docker commit” to make it easy for application developers to quickly adopt the new technology and incorporate it in their existing workflows;
|
||||
|
||||
* Define Docker images as immutable layers, enabling immutable infrastructure. Committed changes are stored as an individual read-only layers, making it easy to re-use images and track changes. Layers also save disk space and network traffic by only transporting the updates instead of entire images;
|
||||
|
||||
* Run Docker containers by instantiating the immutable image with a writable layer that can temporarily store runtime changes, making it easy to deploy and scale multiple instances of the applications quickly.
|
||||
|
||||
Docker grew in popularity, and developers started to move from running containers on their laptops to running them in production. Additional tooling was needed to coordinate these containers across multiple machines, known as container orchestration. Interestingly, one of the first container orchestrators that supported Docker images (June 2014) was [Marathon][3] on Apache Mesos (which we’ll describe in more detail below). That year, Solomon Hykes, founder and CTO of Docker, recommended Mesos as “[the gold standard for production clusters][4]”. Soon after, many container orchestration technologies in addition to Marathon on Mesos emerged: [Nomad][5], [Kubernetes][6] and, not surprisingly, Docker Swarm ([now part of Docker Engine][7]).
|
||||
|
||||
As Docker moved to commercialize the open source file format, the company also started introducing tools to complement the core Docker file format and runtime engine, including:
|
||||
|
||||
* Docker hub for public storage of Docker images;
|
||||
|
||||
* Docker registry for storing it on-premise;
|
||||
|
||||
* Docker cloud, a managed service for building and running containers;
|
||||
|
||||
* Docker datacenter as a commercial offering embodying many Docker technologies.
|
||||
|
||||
![Docker](https://mesosphere.com/wp-content/uploads/2017/07/docker-host.png)
|
||||
|
||||
Source: www.docker.com.
|
||||
|
||||
Docker’s insight to encapsulate software and its dependencies in a single package have been a game changer for the software industry; the same way mp3’s helped to reshape the music industry. The Docker file format became the industry standard, and leading container technology vendors (including Docker, Google, Pivotal, Mesosphere and many others) formed the [Cloud Native Computing Foundation (CNCF)][8] and [Open Container Initiative (OCI)][9]. Today, CNCF and OCI aim to ensure interoperability and standardized interfaces across container technologies and ensure that any Docker container, built using any tools, can run on any runtime or infrastructure.
|
||||
|
||||
### Enter Kubernetes
|
||||
|
||||
Google recognized the potential of the Docker image early on and sought to deliver container orchestration “as-a-service” on the Google Cloud Platform. Google had tremendous experience with containers (they introduced cgroups in Linux) but existing internal container and distributed computing tools like Borg were directly coupled to their infrastructure. So, instead of using any code from their existing systems, Google designed Kubernetes from scratch to orchestrate Docker containers. Kubernetes was released in February 2015 with the following goals and considerations:
|
||||
|
||||
* Empower application developers with a powerful tool for Docker container orchestration without having to interact with the underlying infrastructure;
|
||||
|
||||
* Provide standard deployment interface and primitives for a consistent app deployment experience and APIs across clouds;
|
||||
|
||||
* Build on a Modular API core that allows vendors to integrate systems around the core Kubernetes technology.
|
||||
|
||||
By March 2016, Google [donated Kubernetes][10] to CNCF, and remains today the lead contributor to the project (followed by Redhat, CoreOS and others).
|
||||
|
||||
![Kubernetes](https://mesosphere.com/wp-content/uploads/2017/07/kubernetes-architecture.png)
|
||||
|
||||
Source: wikipedia
|
||||
|
||||
Kubernetes was very attractive for application developers, as it reduced their dependency on infrastructure and operations teams. Vendors also liked Kubernetes because it provided an easy way to embrace the container movement and provide a commercial solution to the operational challenges of running your own Kubernetes deployment (which remains a non-trivial exercise). Kubernetes is also attractive because it is open source under the CNCF, in contrast to Docker Swarm which, though open source, is tightly controlled by Docker, Inc.
|
||||
|
||||
Kubernetes’ core strength is providing application developers powerful tools for orchestrating stateless Docker containers. While there are multiple initiatives to expand the scope of the project to more workloads (like analytics and stateful data services), these initiatives are still in very early phases and it remains to be seen how successful they may be.
|
||||
|
||||
### Apache Mesos
|
||||
|
||||
Apache Mesos started as a UC Berkeley project to create a next-generation cluster manager, and apply the lessons learned from cloud-scale, distributed computing infrastructures such as [Google’s Borg][11] and [Facebook’s Tupperware][12]. While Borg and Tupperware had a monolithic architecture and were closed-source proprietary technologies tied to physical infrastructure, Mesos introduced a modular architecture, an open source development approach, and was designed to be completely independent from the underlying infrastructure. Mesos was quickly adopted by [Twitter][13], [Apple(Siri)][14], [Yelp][15], [Uber][16], [Netflix][17], and many leading technology companies to support everything from microservices, big data and real time analytics, to elastic scaling.
|
||||
|
||||
As a cluster manager, Mesos was architected to solve for a very different set of challenges:
|
||||
|
||||
* Abstract data center resources into a single pool to simplify resource allocation while providing a consistent application and operational experience across private or public clouds;
|
||||
|
||||
* Colocate diverse workloads on the same infrastructure such analytics, stateless microservices, distributed data services and traditional apps to improve utilization and reduce cost and footprint;
|
||||
|
||||
* Automate day-two operations for application-specific tasks such as deployment, self healing, scaling, and upgrades; providing a highly available fault tolerant infrastructure;
|
||||
|
||||
* Provide evergreen extensibility to run new application and technologies without modifying the cluster manager or any of the existing applications built on top of it;
|
||||
|
||||
* Elastically scale the application and the underlying infrastructure from a handful, to tens, to tens of thousands of nodes.
|
||||
|
||||
Mesos has a unique ability to individually manage a diverse set of workloads — including traditional applications such as Java, stateless Docker microservices, batch jobs, real-time analytics, and stateful distributed data services. Mesos’ broad workload coverage comes from its two-level architecture, which enables “application-aware” scheduling. Application-aware scheduling is accomplished by encapsulating the application-specific operational logic in a “Mesos framework” (analogous to a runbook in operations). Mesos Master, the resource manager, then offers these frameworks fractions of the underlying infrastructure while maintaining isolation. This approach allows each workload to have its own purpose-built application scheduler that understands its specific operational requirements for deployment, scaling and upgrade. Application schedulers are also independently developed, managed and updated, allowing Mesos to be highly extensible and support new workloads or add more operational capabilities over time.
|
||||
|
||||
![Mesos two-level scheduler](https://mesosphere.com/wp-content/uploads/2017/07/mesos-two-level-scheduler.png)
|
||||
|
||||
Take, for example, how a team manages upgrades. Stateless application can benefit from a [“blue/green”][18] deployment approach; where another complete version of the app is spun up while the old one is still live, and traffic switches to the new app when ready and the old app is destroyed. But upgrading a data workload like HDFS or Cassandra requires taking the nodes offline one at a time, preserving local data volumes to avoid data loss, performing the upgrade in-place with a specific sequence, and executing special checks and commands on each node type before and after the upgrade. Any of these steps are app or service specific, and may even be version specific. This makes it incredibly challenging to manage data services with a conventional container orchestration scheduler.
|
||||
|
||||
Mesos’ ability to manage each workload the way it wants to be treated has led many companies to use Mesos as a single unified platform to run a combination of microservices and data services together. A common reference architecture for running data-intensive applications is the “[SMACK stack][19]”.
|
||||
|
||||
### A Moment of Clarity
|
||||
|
||||
Notice that we haven’t said anything about container orchestration to describe Apache Mesos. So why do people automatically associate Mesos with container orchestration? Container orchestration is one example of a workload that can run on Mesos’ modular architecture, and it’s done using a specialized orchestration “framework” built on top of Mesos called Marathon. Marathon was originally developed to orchestrate app archives (like JARs, tarballs, ZIP files) in [cgroup][20]containers, and was one of the first container orchestrators to support Docker containers in 2014.
|
||||
|
||||
So when people compare Docker and Kubernetes to Mesos, they are actually comparing Kubernetes and Docker Swarm to Marathon running on Mesos.
|
||||
|
||||
Why does this matter? Because Mesos frankly doesn’t care what’s running on top of it. Mesos can elastically provide cluster services for Java application servers, Docker container orchestration, Jenkins CI Jobs, Apache Spark analytics, Apache Kafka streaming, and more on shared infrastructure. Mesos could even run Kubernetes or other container orchestrators, though a public integration is not yet available.
|
||||
|
||||
![Mesos Workloads](https://mesosphere.com/wp-content/uploads/2017/07/mesos-workloads.png)
|
||||
|
||||
Source: Apache Mesos Survey 2016
|
||||
|
||||
Another consideration for Mesos (and why it’s attractive for many enterprise architects) is its maturity in running mission critical workloads. Mesos has been in large scale production (tens of thousands of servers) for more than 7 years, which is why it’s known to be more production ready and reliable at scale than many other container-enabling technologies in the market.
|
||||
|
||||
### What does this all mean?
|
||||
|
||||
In summary, all three technologies have something to do with Docker containers and give you access to container orchestration for application portability and scale. So how do you choose between them? It comes down to choosing the right tool for the job (and perhaps even different ones for different jobs). If you are an application developer looking for a modern way to build and package your application, or to accelerate microservices initiatives, the Docker container format and developer tooling is the best way to do so.
|
||||
|
||||
If you are a dev/devops team and want to build a system dedicated exclusively to Docker container orchestration, and are willing to get your hands dirty integrating your solution with the underlying infrastructure (or rely on public cloud infrastructure like Google Container Engine or Azure Container Service), Kubernetes is a good technology for you to consider.
|
||||
|
||||
If you want to build a reliable platform that runs multiple mission critical workloads including Docker containers, legacy applications (e.g., Java), and distributed data services (e.g., Spark, Kafka, Cassandra, Elastic), and want all of this portable across cloud providers and/or datacenters, then Mesos (or our own Mesos distribution, Mesosphere DC/OS) is the right fit for you.
|
||||
|
||||
Whatever you choose, you’ll be embracing a set of tools that makes more efficient use of server resources, simplifies application portability, and increases developer agility. You really can’t go wrong.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://mesosphere.com/blog/docker-vs-kubernetes-vs-apache-mesos/?from=timeline&isappinstalled=0&nsukey=b2Ig6wj1rvlgVuEZ8ens0KVLuxYx7zv7GLuL1KBpcSWpvkfF2nHcSqeKJ7JnP%2FckIM4vBaRUkwdlUpWHNzrY8va0G14sN323y7T7OEix0DZpQOUQ%2FeiRcA7wJWN3Rws4PVSSI0wapm%2Bl5jCf%2B%2Bbj5HioS%2B%2FOeeil79KMIFrgFjKRMRWwZvlbOyq4j4iaipOi
|
||||
|
||||
作者:[Amr Abdelrazik ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://mesosphere.com/blog/author/amr-abdelrazik/
|
||||
[1]:https://en.wikipedia.org/wiki/Cgroups
|
||||
[2]:https://docs.docker.com/engine/docker-overview/
|
||||
[3]:https://mesosphere.github.io/marathon/
|
||||
[4]:https://www.google.com/url?q=https://www.youtube.com/watch?v=sGWQ8WiGN8Y&feature=youtu.be&t=35m10s&sa=D&ust=1500923856666000&usg=AFQjCNFLtW96ZWnOUGFPX_XUuVOPdWrd_w
|
||||
[5]:https://www.nomadproject.io/
|
||||
[6]:http://kubernetes.io/
|
||||
[7]:https://blog.docker.com/2016/06/docker-1-12-built-in-orchestration/
|
||||
[8]:https://www.cncf.io/
|
||||
[9]:https://www.opencontainers.org/
|
||||
[10]:https://www.linuxfoundation.org/news-media/announcements/2016/03/cloud-native-computing-foundation-accepts-kubernetes-first-hosted-0
|
||||
[11]:https://research.google.com/pubs/pub43438.html
|
||||
[12]:https://www.youtube.com/watch?v=C_WuUgTqgOc
|
||||
[13]:https://youtu.be/F1-UEIG7u5g
|
||||
[14]:http://www.businessinsider.com/apple-siri-uses-apache-mesos-2015-8
|
||||
[15]:https://engineeringblog.yelp.com/2015/11/introducing-paasta-an-open-platform-as-a-service.html
|
||||
[16]:http://highscalability.com/blog/2016/9/28/how-uber-manages-a-million-writes-per-second-using-mesos-and.html
|
||||
[17]:https://medium.com/netflix-techblog/distributed-resource-scheduling-with-apache-mesos-32bd9eb4ca38
|
||||
[18]:https://martinfowler.com/bliki/BlueGreenDeployment.html
|
||||
[19]:https://mesosphere.com/blog/2017/06/21/smack-stack-new-lamp-stack/
|
||||
[20]:https://en.wikipedia.org/wiki/Cgroups
|
||||
[21]:https://mesosphere.com/blog/author/amr-abdelrazik/
|
@ -0,0 +1,276 @@
|
||||
Deploy Kubernetes cluster for Linux containers
|
||||
============================================================
|
||||
|
||||
In this quick start, a Kubernetes cluster is deployed using the Azure CLI. A multi-container application consisting of web front-end and a Redis instance is then deployed and run on the cluster. Once completed, the application is accessible over the internet.
|
||||
|
||||
![Image of browsing to Azure Vote](https://docs.microsoft.com/en-us/azure/container-service/kubernetes/media/container-service-kubernetes-walkthrough/azure-vote.png)
|
||||
|
||||
This quick start assumes a basic understanding of Kubernetes concepts, for detailed information on Kubernetes see the [Kubernetes documentation][3].
|
||||
|
||||
If you don't have an Azure subscription, create a [free account][4] before you begin.
|
||||
|
||||
### Launch Azure Cloud Shell
|
||||
|
||||
The Azure Cloud Shell is a free Bash shell that you can run directly within the Azure portal. It has the Azure CLI preinstalled and configured to use with your account. Click the Cloud Shell button on the menu in the upper-right of the [Azure portal][5].
|
||||
|
||||
[![Cloud Shell](https://docs.microsoft.com/en-us/azure/includes/media/cloud-shell-try-it/cloud-shell-menu.png)][6]
|
||||
|
||||
The button launches an interactive shell that you can use to run all of the steps in this topic:
|
||||
|
||||
[![Screenshot showing the Cloud Shell window in the portal](https://docs.microsoft.com/en-us/azure/includes/media/cloud-shell-try-it/cloud-shell-safari.png)][7]
|
||||
|
||||
If you choose to install and use the CLI locally, this quickstart requires that you are running the Azure CLI version 2.0.4 or later. Run `az --version` to find the version. If you need to install or upgrade, see [Install Azure CLI 2.0][8].
|
||||
|
||||
### Create a resource group
|
||||
|
||||
Create a resource group with the [az group create][9] command. An Azure resource group is a logical group in which Azure resources are deployed and managed.
|
||||
|
||||
The following example creates a resource group named _myResourceGroup_ in the _eastus_ location.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
az group create --name myResourceGroup --location eastus
|
||||
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
JSONCopy
|
||||
|
||||
```
|
||||
{
|
||||
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup",
|
||||
"location": "eastus",
|
||||
"managedBy": null,
|
||||
"name": "myResourceGroup",
|
||||
"properties": {
|
||||
"provisioningState": "Succeeded"
|
||||
},
|
||||
"tags": null
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Create Kubernetes cluster
|
||||
|
||||
Create a Kubernetes cluster in Azure Container Service with the [az acs create][10]command. The following example creates a cluster named _myK8sCluster_ with one Linux master node and three Linux agent nodes.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
az acs create --orchestrator-type=kubernetes --resource-group myResourceGroup --name=myK8sCluster --generate-ssh-keys
|
||||
|
||||
```
|
||||
|
||||
After several minutes, the command completes and returns json formatted information about the cluster.
|
||||
|
||||
### Connect to the cluster
|
||||
|
||||
To manage a Kubernetes cluster, use [kubectl][11], the Kubernetes command-line client.
|
||||
|
||||
If you're using Azure CloudShell, kubectl is already installed. If you want to install it locally, you can use the [az acs kubernetes install-cli][12] command.
|
||||
|
||||
To configure kubectl to connect to your Kubernetes cluster, run the [az acs kubernetes get-credentials][13] command. This steps downloads credentials and configures the Kubernetes CLI to use them.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
az acs kubernetes get-credentials --resource-group=myResourceGroup --name=myK8sCluster
|
||||
|
||||
```
|
||||
|
||||
To verify the connection to your cluster, use the [kubectl get][14] command to return a list of the cluster nodes.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
kubectl get nodes
|
||||
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
bashCopy
|
||||
|
||||
```
|
||||
NAME STATUS AGE VERSION
|
||||
k8s-agent-14ad53a1-0 Ready 10m v1.6.6
|
||||
k8s-agent-14ad53a1-1 Ready 10m v1.6.6
|
||||
k8s-agent-14ad53a1-2 Ready 10m v1.6.6
|
||||
k8s-master-14ad53a1-0 Ready,SchedulingDisabled 10m v1.6.6
|
||||
|
||||
```
|
||||
|
||||
### Run the application
|
||||
|
||||
A Kubernetes manifest file defines a desired state for the cluster, including things like what container images should be running. For this example, a manifest is used to create all object needed to run the Azure Vote application.
|
||||
|
||||
Create a file named `azure-vote.yaml` and copy into it the following YAML.
|
||||
|
||||
yamlCopy
|
||||
|
||||
```
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: azure-vote-back
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: azure-vote-back
|
||||
spec:
|
||||
containers:
|
||||
- name: azure-vote-back
|
||||
image: redis
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: azure-vote-back
|
||||
spec:
|
||||
ports:
|
||||
- port: 6379
|
||||
selector:
|
||||
app: azure-vote-back
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: azure-vote-front
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: azure-vote-front
|
||||
spec:
|
||||
containers:
|
||||
- name: azure-vote-front
|
||||
image: microsoft/azure-vote-front:redis-v1
|
||||
ports:
|
||||
- containerPort: 80
|
||||
env:
|
||||
- name: REDIS
|
||||
value: "azure-vote-back"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: azure-vote-front
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- port: 80
|
||||
selector:
|
||||
app: azure-vote-front
|
||||
|
||||
```
|
||||
|
||||
Use the [kubectl create][15] command to run the application.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
kubectl create -f azure-vote.yaml
|
||||
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
bashCopy
|
||||
|
||||
```
|
||||
deployment "azure-vote-back" created
|
||||
service "azure-vote-back" created
|
||||
deployment "azure-vote-front" created
|
||||
service "azure-vote-front" created
|
||||
|
||||
```
|
||||
|
||||
### Test the application
|
||||
|
||||
As the application is run, a [Kubernetes service][16] is created that exposes the application front-end to the internet. This process can take a few minutes to complete.
|
||||
|
||||
To monitor progress, use the [kubectl get service][17] command with the `--watch`argument.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
kubectl get service azure-vote-front --watch
|
||||
|
||||
```
|
||||
|
||||
Initially the EXTERNAL-IP for the _azure-vote-front_ service appears as _pending_ . Once the EXTERNAL-IP address has changed from _pending_ to an _IP address_ , use `CTRL-C` to stop the kubectl watch process.
|
||||
|
||||
bashCopy
|
||||
|
||||
```
|
||||
azure-vote-front 10.0.34.242 <pending> 80:30676/TCP 7s
|
||||
azure-vote-front 10.0.34.242 52.179.23.131 80:30676/TCP 2m
|
||||
|
||||
```
|
||||
|
||||
You can now browse to the external IP address to see the Azure Vote App.
|
||||
|
||||
![Image of browsing to Azure Vote](https://docs.microsoft.com/en-us/azure/container-service/kubernetes/media/container-service-kubernetes-walkthrough/azure-vote.png)
|
||||
|
||||
### Delete cluster
|
||||
|
||||
When the cluster is no longer needed, you can use the [az group delete][18]command to remove the resource group, container service, and all related resources.
|
||||
|
||||
Azure CLICopyTry It
|
||||
|
||||
```
|
||||
az group delete --name myResourceGroup --yes --no-wait
|
||||
|
||||
```
|
||||
|
||||
### Get the code
|
||||
|
||||
In this quick start, pre-created container images have been used to create a Kubernetes deployment. The related application code, Dockerfile, and Kubernetes manifest file are available on GitHub.+
|
||||
|
||||
[https://github.com/Azure-Samples/azure-voting-app-redis][19]
|
||||
|
||||
### Next steps
|
||||
|
||||
In this quick start, you deployed a Kubernetes cluster and deployed a multi-container application to it.
|
||||
|
||||
To learn more about Azure Container Service, and walk through a complete code to deployment example, continue to the Kubernetes cluster tutorial.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://docs.microsoft.com/en-us/azure/container-service/kubernetes/container-service-kubernetes-walkthrough
|
||||
|
||||
作者:[neilpeterson ][a],[mmacy][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://github.com/neilpeterson
|
||||
[b]:https://github.com/mmacy
|
||||
[1]:https://github.com/neilpeterson
|
||||
[2]:https://github.com/mmacy
|
||||
[3]:https://kubernetes.io/docs/home/
|
||||
[4]:https://azure.microsoft.com/free/?WT.mc_id=A261C142F
|
||||
[5]:https://portal.azure.com/
|
||||
[6]:https://portal.azure.com/
|
||||
[7]:https://portal.azure.com/
|
||||
[8]:https://docs.microsoft.com/en-us/cli/azure/install-azure-cli
|
||||
[9]:https://docs.microsoft.com/en-us/cli/azure/group#create
|
||||
[10]:https://docs.microsoft.com/en-us/cli/azure/acs#create
|
||||
[11]:https://kubernetes.io/docs/user-guide/kubectl/
|
||||
[12]:https://docs.microsoft.com/en-us/cli/azure/acs/kubernetes#install-cli
|
||||
[13]:https://docs.microsoft.com/en-us/cli/azure/acs/kubernetes#get-credentials
|
||||
[14]:https://kubernetes.io/docs/user-guide/kubectl/v1.6/#get
|
||||
[15]:https://kubernetes.io/docs/user-guide/kubectl/v1.6/#create
|
||||
[16]:https://kubernetes.io/docs/concepts/services-networking/service/
|
||||
[17]:https://kubernetes.io/docs/user-guide/kubectl/v1.6/#get
|
||||
[18]:https://docs.microsoft.com/en-us/cli/azure/group#delete
|
||||
[19]:https://github.com/Azure-Samples/azure-voting-app-redis.git
|
570
translated/tech/20170312 OpenGL Go Tutorial Part 1.md
Normal file
570
translated/tech/20170312 OpenGL Go Tutorial Part 1.md
Normal file
@ -0,0 +1,570 @@
|
||||
OpenGL 与 Go 教程 第一节: Hello, OpenGL
|
||||
============================================================
|
||||
|
||||
_[第一节: Hello, OpenGL][6]_ | _[第二节: 绘制游戏面板][7]_ | _[第三节: 实现游戏功能][8]_
|
||||
|
||||
_这篇教程的所有源代码都可以在 [GitHub][9] 上找到。_
|
||||
|
||||
### 介绍
|
||||
|
||||
[OpenGL][19] 是一门相当好的技术,适用于多种类型的绘图工作,从桌面的 GUI 到游戏,到移动应用甚至 web 应用。我敢保证,你今天看到的图形有些就是用 OpenGL 渲染的。可是,不管 OpenGL 多受欢迎、有多好用,与学习其它高层次的绘图库相比,学习 OpenGL 是要相当足够的决心的。
|
||||
|
||||
这个教程的目的是给你一个切入点,让你对 OpenGL 有个基本的了解,然后教你怎么用 [Go][20] 操作它。几乎每种编程语言都有绑定 OpenGL 的库,Go 也不例外,它有 [go-gl][21] 这个包。这是一个完整的套件,可以绑定 OpenGL ,适用于多种版本的 OpenGL。
|
||||
|
||||
这篇教程会按照下面列出的几个阶段进行介绍,我们最终的目标是用 OpenGL 在桌面窗口绘制游戏面板,进而实现 [Conway's Game of Life][22]。完整的源代码可以在 GitHub [github.com/KyleBanks/conways-gol][23] 上获得,当你有疑惑的时候可以随时查看源代码,或者你要按照自己的方式学习也可以参考这个代码。
|
||||
|
||||
在我们开始之前,我们要先弄明白 _Conway's Game of Life_ 到底是什么。这里是 [Wikipedia][24] 上面的总结:
|
||||
|
||||
> 《Game of Life》,也可以简称为 Life,是一个细胞自动变化的过程,由英国数学家 John Horton Conway 于 1970 年提出。
|
||||
>
|
||||
> 这个“游戏”没有玩家,也就是说它的发展依靠的是它的初始状态,不需要输入。用户通过创建初始配置文件、观察它如何演变,或者对于高级“玩家”可以创建特殊属性的模式,进而与《Game of Life》进行交互。
|
||||
>
|
||||
> 规则
|
||||
>
|
||||
> 《Game of Life》的世界是一个无穷多的二维正交的正方形细胞的格子,每一个格子都有两种可能的状态,“存活”或者“死亡”,也可以说是“填充态”或“未填充态”(区别可能很小,除非把它看作一个模拟人类/哺乳动物行为的早期模型,或者在一个人如何看待方格里的空白时)。每一个细胞与它周围的八个细胞相关联,这八个细胞分别是水平、垂直、斜对角相接的。在游戏中的每一步,下列事情中的一件将会发生:
|
||||
>
|
||||
> 1. 任何存活着的细胞当任何一个存活的 cell 的附近少于 2 个存活的 cell 时,该 cell 将会消亡,就像人口过少所导致的结果一样
|
||||
> 2. 当任何一个存活的 cell 的附近有 2 至 3 个存活的 cell 时,该 cell 在下一代中仍然存活。
|
||||
> 3. 当任何一个存活的 cell 的附近多于 3 个存活的 cell 时,该 cell 将会消亡,就像人口过多所导致的结果一样
|
||||
> 4. 任何一个消亡的 cell 附近刚好有 3 个存活的 cell,该 cell 会变为存活的状态,就像重生一样。
|
||||
|
||||
不需要其他工具,这里由一个我们将会制作的演示程序:
|
||||
|
||||
![OpenGL 与 Go 语言教程中的 Conway's Game of Life - 示例游戏](https://kylewbanks.com/images/post/golang-opengl-conway-1.gif)
|
||||
|
||||
在我们的运行过程中,白色的细胞表示它是存活着的,黑色的细胞表示它已经死亡。
|
||||
|
||||
### 概述
|
||||
|
||||
本教程将会涉及到很多基础内容,从最基本的开始,但是你还是要对 Go 由一些最基本的了解 - 至少你应该知道变量,切片,函数和结构体,并且装了一个 Go 的运行环境。我写这篇教程用的 Go 版本是 1.8,但它应该与之前的版本兼容。这里用 Go 语言实现没有什么特别新奇的东西,因此只要你有过类似的编程经历就行。
|
||||
|
||||
这里是我们在这个教程里将会讲到的东西:
|
||||
|
||||
* [第一节: Hello, OpenGL][10]: 安装 OpenGL 和 [GLFW][11],在窗口上绘制一个三角形。
|
||||
* [第二节: 绘制游戏面板][12]: 用三角形拼成方形,在窗口上用方形绘成格子。
|
||||
* [第三节: 实现游戏功能][13]: 实现 Conway 游戏
|
||||
|
||||
最后的源代码可以在 [GitHub][25] 上获得,每一节的末尾有个_回顾_,包含该节相关的代码。如果有什么不清楚的地方或者是你感到疑惑的,看看每一节末尾的完整代码。
|
||||
|
||||
现在就开始吧!
|
||||
|
||||
### 安装 OpenGL 和 GLFW
|
||||
|
||||
我们介绍过 OpenGL,但是为了使用它,我们要有个窗口可以绘制东西。 [GLFW][26] 是一款对于 OpenGL 跨平台的 API,允许我们创建窗口并使用,而且它是 [go-gl][27] 套件中提供的。
|
||||
|
||||
我们要做的第一件事就是确定 OpenGL 的版本。为了方便本教程,我们将会使用 **OpenGL v4.1**,但你也可以用 **v2.1** 要是你的操作系统不支持最新的 OpenGL。要安装 OpenGL,我们需要做这些事:
|
||||
|
||||
```
|
||||
# 对于 OpenGL 4.1
|
||||
$ go get github.com/go-gl/gl/v4.1-core/gl
|
||||
|
||||
# 或者 2.1
|
||||
$ go get github.com/go-gl/gl/v2.1/gl
|
||||
```
|
||||
|
||||
然后是安装 GLFW:
|
||||
|
||||
```
|
||||
$ go get github.com/go-gl/glfw/v3.2/glfw
|
||||
```
|
||||
|
||||
安装好这两个包之后,我们就可以开始了!先创建 **main.go** 文件,导入相应的包(我们待会儿会用到的其他东西)。
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl" // OR: github.com/go-gl/gl/v2.1/gl
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
)
|
||||
```
|
||||
|
||||
Next lets define the **main** function, the purpose of which is to initialize OpenGL and GLFW and display the window:
|
||||
接下来定义一个叫做 **main** 的函数,这是用来初始化 OpenGL 以及 GLFW,显示窗口的:
|
||||
|
||||
```
|
||||
const (
|
||||
width = 500
|
||||
height = 500
|
||||
)
|
||||
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window := initGlfw()
|
||||
defer glfw.Terminate()
|
||||
|
||||
for !window.ShouldClose() {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
// initGlfw 初始化 glfw 并且返回一个可用的窗口。
|
||||
func initGlfw() *glfw.Window {
|
||||
if err := glfw.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
glfw.WindowHint(glfw.Resizable, glfw.False)
|
||||
glfw.WindowHint(glfw.ContextVersionMajor, 4) // OR 2
|
||||
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
||||
|
||||
window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
window.MakeContextCurrent()
|
||||
|
||||
return window
|
||||
}
|
||||
```
|
||||
|
||||
好了,让我们花一分钟来运行一下这个程序,看看会发生什么。首先定义了一些常量, **width** 和 **height** - 它们决定窗口的像素大小。
|
||||
|
||||
然后就是 **main** 函数。这里我们使用了 **runtime** 包的 **LockOSThread()**,这能确保我们总是在操作系统的一个线程中运行代码,这对 GLFW 来说很重要,GLFW 被初始化之后需要在同一个进程里被调用多次。讲完这个,接下来我们调用 **initGlfw** 来获得一个窗口的引用,并且 defer glfw 的 terminating 方法。窗口的引用会被用在一个 for 循环中,只要窗口是打开的状态,就执行某些事情。我们待会儿会讲要做的事情是什么。
|
||||
|
||||
**initGlfw** 是另一个函数,这里我们调用 **glfw.Init()** 来初始化 GLFW 包。然后我们定义了 GLFW 的一些全局属性,包括禁用调整窗口大小和改变 OpenGL 的属性。然后创建了 **glfw.Window**,这会在稍后的绘图中用到。我们仅仅告诉它我们想要的宽度和高度,以及标题,然后调用 **window.MakeContextCurrent**,将窗口绑定到当前的进程中。最后就是返回窗口的引用了。
|
||||
|
||||
如果你现在就构建、运行这个程序,你看不到任何东西。很合理,因为我们还没有用这个窗口做什么实质性的事。
|
||||
|
||||
定义一个新函数,初始化 OpenGL,就可以解决这个问题:
|
||||
|
||||
```
|
||||
// initOpenGL 初始化 OpenGL 并且返回一个初始化了的程序。
|
||||
func initOpenGL() uint32 {
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
prog := gl.CreateProgram()
|
||||
gl.LinkProgram(prog)
|
||||
return prog
|
||||
}
|
||||
```
|
||||
|
||||
**initOpenGL** 就像之前的 **initGlfw** 函数一样,初始化 OpenGL 库,创建一个_程序_。这个程序是一个包含了着色器的引用,稍后会用于绘图。待会儿会讲这一点,现在只用知道 OpenGL 已经初始化完成了,我们有一个 **program** 的引用。我们还打印了 OpenGL 的版本,这对于 debug 很有帮助。
|
||||
|
||||
回到 **main** 函数里,调用这个新函数:
|
||||
|
||||
```
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window := initGlfw()
|
||||
defer glfw.Terminate()
|
||||
|
||||
program := initOpenGL()
|
||||
|
||||
for !window.ShouldClose() {
|
||||
draw(window, program)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
你应该注意到了现在我们有 **program** 的引用,在我们的窗口循环中,调用新的 **draw** 函数。最终这个函数会绘制出所有细胞,让游戏状态变得可视化,但是现在它做的仅仅是情况窗口,所以我们只能看到一个全黑的屏幕:
|
||||
|
||||
```
|
||||
func draw(window *glfw.Window, program uint32) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.UseProgram(prog)
|
||||
|
||||
glfw.PollEvents()
|
||||
window.SwapBuffers()
|
||||
}
|
||||
```
|
||||
|
||||
我们首先做的是调用 **gl.clear** 函数来清除上一帧在窗口中绘制的东西,给我们一个干净的面板。然后我们告诉 OpenGL 去使用程序引用,这个引用还没有做什么事。最终我们告诉 GLFW 用 **PollEvents** 去检查是否有鼠标或者键盘事件(这一节里还不会对这些事件进行处理),告诉窗口 **SwapBuffers**。 [Buffer swapping][28](交换缓冲区) 很重要,因为 GLFW(像其他图形库一样)使用双缓冲,也就是说你绘制的所有东西实际上是绘制到一个不可见的画布上,当你准备好进行展示的时候就把绘制的这些东西放到可见的画布中 - 这种情况下,就需要调用 **SwapBuffers** 函数。
|
||||
|
||||
好了,到这里我们已经讲了很多东西,花一点时间看看我们的实验成果。运行这个程序,你应该可以看到你所绘制的第一个东西:
|
||||
|
||||
![OpenGL 与 Go 语言教程中的 Conway's Game of Life - 第一个窗口](https://kylewbanks.com/images/post/golang-opengl-conway-2.png)
|
||||
|
||||
完美!
|
||||
|
||||
### 在窗口里绘制三角形
|
||||
|
||||
我们已经完成了一些复杂的步骤,即使看上去和图片不像,但我们仍然需要绘制一些东西。我们会以三角形绘制开始,可能这第一眼看上去要比我们最终要绘制的方形更难,但你会知道这样的想法是错的。你可能不知道的是三角形或许是绘制的图形中最简单的,实际上我们最终会用某种方式把三角形拼成方形。
|
||||
|
||||
好吧,那么我们想要绘制一个三角形,怎么做呢?我们通过定义图形的顶点来绘制图形,把它们交给 OpenGL 来进行绘制。先在 **main.go** 的顶部里定义我们的三角形:
|
||||
|
||||
```
|
||||
var (
|
||||
triangle = []float32{
|
||||
0, 0.5, 0, // top
|
||||
-0.5, -0.5, 0, // left
|
||||
0.5, -0.5, 0, // right
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
这看上去很奇怪,让我们分开来看。首先我们用了一个 **float32** 切片(slice),这是一种我们总会在向 OpenGL 传递顶点时用到的数据类型。这个切片包含 9 个值,每三个值构成三角形的一个点。第一行, **0, 0.5, 0** 表示的是 X、Y、Z 坐标,是最上方的顶点,第二行是左边的顶点,第三行是右边的顶点。每一组的三个点都表示相对于窗口中心点的 X、Y、Z 坐标,在 **-1 和 1** 之间。因此最上面的顶点 X 坐标是 0,因为它在 X 方向上位于窗口中央,Y 坐标是 _0.5_ 意味着它会相对窗口中央上移 1/4 个单位(因为窗口的范围是 -1 到 1),Z 坐标是 0.因为我们只需要在二维空间中绘图,所以 Z 值永远是 0。现在看一看左右两边的顶点,看看你能不能理解为什么它们是这样定义的 —— 如果不能立刻就弄清楚也没关系,我们将会在屏幕上去观察它,因此我们需要一个完美的图形来进行观察。
|
||||
|
||||
好了,我们定义了一个三角形,但是现在我们得把它画出来。要画出这个三角形,我们需要一个叫做 **Vertex Array Object** 或者叫 **vao** 的东西,这是由一系列的点(也就是我们定义的三角形)创造的,这个东西可以提供给 OpenGL 来进行绘制。创建一个叫做 **makeVao** 的函数,然后我们可以提供一组切片的点,让它返回一个指向 OpenGL vertex array object 的指针:
|
||||
|
||||
```
|
||||
// makeVao 执行初始化并从提供的点里面返回一个顶点数组
|
||||
func makeVao(points []float32) uint32 {
|
||||
var vbo uint32
|
||||
gl.GenBuffers(1, &vbo)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
|
||||
|
||||
var vao uint32
|
||||
gl.GenVertexArrays(1, &vao)
|
||||
gl.BindVertexArray(vao)
|
||||
gl.EnableVertexAttribArray(0)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
|
||||
|
||||
return vao
|
||||
}
|
||||
```
|
||||
|
||||
首先我们创造了 **Vertex Buffer Object** 或者说 **vbo** 绑定到我们的 **vao** 上,**vbo** 是通过所占空间(也就是**4 x len(points)**大小的空间)和一个指向顶点的指针(**gl.Ptr(points)**)来创建的。你也许会好奇为什么它是 **4 x len(points)** - 而不是 6 或者 3 或者 1078 呢?原因在于我们用的是 **float32** 切片,32 个 bit 的 float 浮点型变量是 4 个字节,因此我们说这个缓冲区以字节为单位的大小是点个数的 4 倍。
|
||||
|
||||
现在我们有缓冲区了,可以创建 **vao** 并用 **gl.BindBuffer** 把它绑定到缓冲区上,最后返回 **vao**。这个 **vao** 将会被用于绘制三角形!
|
||||
|
||||
回到 **main** 函数:
|
||||
|
||||
```
|
||||
func main() {
|
||||
...
|
||||
|
||||
vao := makeVao(triangle)
|
||||
for !window.ShouldClose() {
|
||||
draw(vao, window, program)
|
||||
}
|
||||
}
|
||||
|
||||
这里我们调用了 **makeVao** ,从我们之前定义的 **triangle** 顶点中获得 **vao** 引用,将它作为一个新的参数传递给 **draw** 函数:
|
||||
|
||||
func draw(vao uint32, window *glfw.Window, program uint32) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.UseProgram(program)
|
||||
|
||||
gl.BindVertexArray(vao)
|
||||
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle) / 3))
|
||||
|
||||
glfw.PollEvents()
|
||||
window.SwapBuffers()
|
||||
}
|
||||
```
|
||||
|
||||
然后我们把 OpenGL 绑定到 **vao** 上,这样当我们告诉 OpenGL 三角形切片的顶点数(除以 3,是因为每一个点有 X、Y、Z 坐标),让它去 **DrawArrays** ,它就知道要画多少个顶点了。
|
||||
|
||||
如果你这时候运行程序,你可能希望在窗口中央看到一个美丽的三角形,但是不幸的是你还看不到。还有一件事情没做,我们告诉 OpenGL 我们要画一个三角形,但是我们还要告诉它_怎么_画出来。
|
||||
|
||||
要让它画出来,我们需要叫做片元着色器和顶点着色器的东西,这些已经超出本教程的范围了(老实说,也超出了我对 OpenGL 的了解),但 [Harold Serrano On Quora][29] 关于它们是什么给出了完美的介绍。我们只需要理解,对于这个应用来说,着色器是它内部的小程序(用 [OpenGL Shader Language or GLSL][30] 编写的),操作顶点进行绘制,也可用于确定图形的颜色。
|
||||
|
||||
添加两个 imports 和一个叫做 **compileShader** 的函数:
|
||||
|
||||
```
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func compileShader(source string, shaderType uint32) (uint32, error) {
|
||||
shader := gl.CreateShader(shaderType)
|
||||
|
||||
csources, free := gl.Strs(source)
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
free()
|
||||
gl.CompileShader(shader)
|
||||
|
||||
var status int32
|
||||
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
|
||||
if status == gl.FALSE {
|
||||
var logLength int32
|
||||
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
|
||||
|
||||
log := strings.Repeat("\x00", int(logLength+1))
|
||||
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
|
||||
|
||||
return 0, fmt.Errorf("failed to compile %v: %v", source, log)
|
||||
}
|
||||
|
||||
return shader, nil
|
||||
}
|
||||
```
|
||||
|
||||
这个函数的目的是以字符串的形式接受着色器源代码和它的类型,然后返回一个指向这个编译好的着色器的指针。如果编译失败,我们就会获得出错的详细信息。
|
||||
|
||||
现在定义着色器,在 **makeProgram** 里编译。回到我们的 **const** 块中,我们在这里定义了 **width** 和 **hegiht**。
|
||||
|
||||
```
|
||||
vertexShaderSource = `
|
||||
#version 410
|
||||
in vec3 vp;
|
||||
void main() {
|
||||
gl_Position = vec4(vp, 1.0);
|
||||
}
|
||||
` + "\x00"
|
||||
|
||||
fragmentShaderSource = `
|
||||
#version 410
|
||||
out vec4 frag_colour;
|
||||
void main() {
|
||||
frag_colour = vec4(1, 1, 1, 1);
|
||||
}
|
||||
` + "\x00"
|
||||
```
|
||||
|
||||
你能看到这是两个着色器程序,包含了 GLSL 源代码的字符串,一个是_顶点着色器_,另一个是_片元着色器_。唯一比较特殊的地方是它们都要在末尾加上一个空终止字符,**\x00** —— OpenGL 需要它才能编译着色器。注意 **fragmentShaderSource**,这是我们用 RGBA 形式的值通过 **vec4** 来定义我们图形的颜色。你可以修改这里的值来改变这个三角形的颜色,现在的值是 **RGBA(1, 1, 1, 1)** 或者说是 _white_。
|
||||
|
||||
同样需要注意的是这两个程序都是运行在 **#version 410** 版本下,如果你用的是 OpenGL 2.1,那你也可以改成 **#version 120**。**120** 不是打错的,如果你用的是 OpenGL 2.1,要用 **120** 而不是 **210**!
|
||||
|
||||
接下来在 **initOpenGL** 中我们会编译着色器,把它们附加到我们的 **program** 中。
|
||||
|
||||
```
|
||||
func initOpenGL() uint32 {
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prog := gl.CreateProgram()
|
||||
gl.AttachShader(prog, vertexShader)
|
||||
gl.AttachShader(prog, fragmentShader)
|
||||
gl.LinkProgram(prog)
|
||||
return prog
|
||||
}
|
||||
```
|
||||
|
||||
这里我们用 _顶点着色器_ 调用了 **compileShader** 函数,指定它的类型是 **gl.VERTEX_SHADER**,对 _片元着色器_ 做了同样的事情,但是指定的类型是 **gl.FRAGMENT_SHADER**。编译完成后,我们把它们附加到程序中,调用 **gl.AttachShader**,传递程序以及编译好的着色器。
|
||||
|
||||
现在我们终于可以看到我们漂亮的三角形了!运行程序,如果一切顺利的话你会看到这些:
|
||||
|
||||
![OpenGL 与 Go 语言教程中的 Conway's Game of Life - Hello, Triangle!](https://kylewbanks.com/images/post/golang-opengl-conway-3.png)
|
||||
|
||||
### 总结
|
||||
|
||||
是不是很惊喜!这些代码画出了一个三角形,但我保证我们已经完成了大部分的 OpenGL 代码,在接下来的章节中我们还会用到这些代码。我十分推荐你花几分钟修改一下代码,看看你能不能移动三角形,改变三角形的大小和颜色。OpenGL 可以令人心生畏惧,有时想要理解发生了什么很困难,但是要记住,这不是魔术 - 它就是它看上去的东西。
|
||||
|
||||
下一节里我们讲会用两个锐角三角形拼出一个方形 - 看看你能不能试着修改这一节的代码,再进入下一节。不能也没有关系,因为我们在 [第二节][31] 还会编写代码, 按照创建一个有许多方形的格子,我们把它当做游戏面板。
|
||||
|
||||
最后,在[第三节][32] 里我们会用格子来实现 _Conway’s Game of Life_!
|
||||
|
||||
_[第一节: Hello, OpenGL][14]_ | _[第二节: 绘制游戏面板][15]_ | _[第三节:实现游戏功能][16]_
|
||||
|
||||
_本教程的完整源代码可在 [GitHub][17] 上获得。_
|
||||
|
||||
### 回顾
|
||||
|
||||
本教程 **main.go** 文件的内容如下:
|
||||
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl" // OR: github.com/go-gl/gl/v2.1/gl
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
)
|
||||
|
||||
const (
|
||||
width = 500
|
||||
height = 500
|
||||
|
||||
vertexShaderSource = `
|
||||
#version 410
|
||||
in vec3 vp;
|
||||
void main() {
|
||||
gl_Position = vec4(vp, 1.0);
|
||||
}
|
||||
` + "\x00"
|
||||
|
||||
fragmentShaderSource = `
|
||||
#version 410
|
||||
out vec4 frag_colour;
|
||||
void main() {
|
||||
frag_colour = vec4(1, 1, 1, 1.0);
|
||||
}
|
||||
` + "\x00"
|
||||
)
|
||||
|
||||
var (
|
||||
triangle = []float32{
|
||||
0, 0.5, 0,
|
||||
-0.5, -0.5, 0,
|
||||
0.5, -0.5, 0,
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window := initGlfw()
|
||||
defer glfw.Terminate()
|
||||
program := initOpenGL()
|
||||
|
||||
vao := makeVao(triangle)
|
||||
for !window.ShouldClose() {
|
||||
draw(vao, window, program)
|
||||
}
|
||||
}
|
||||
|
||||
func draw(vao uint32, window *glfw.Window, program uint32) {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.UseProgram(program)
|
||||
|
||||
gl.BindVertexArray(vao)
|
||||
gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle)/3))
|
||||
|
||||
glfw.PollEvents()
|
||||
window.SwapBuffers()
|
||||
}
|
||||
|
||||
// initGlfw 初始化 glfw 并返回一个窗口供使用。
|
||||
func initGlfw() *glfw.Window {
|
||||
if err := glfw.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
glfw.WindowHint(glfw.Resizable, glfw.False)
|
||||
glfw.WindowHint(glfw.ContextVersionMajor, 4)
|
||||
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
||||
|
||||
window, err := glfw.CreateWindow(width, height, "Conway's Game of Life", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
window.MakeContextCurrent()
|
||||
|
||||
return window
|
||||
}
|
||||
|
||||
// initOpenGL 初始化 OpenGL 并返回一个已经编译好的着色器程序
|
||||
func initOpenGL() uint32 {
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
prog := gl.CreateProgram()
|
||||
gl.AttachShader(prog, vertexShader)
|
||||
gl.AttachShader(prog, fragmentShader)
|
||||
gl.LinkProgram(prog)
|
||||
return prog
|
||||
}
|
||||
|
||||
// makeVao 执行初始化并从提供的点里面返回一个顶点数组
|
||||
func makeVao(points []float32) uint32 {
|
||||
var vbo uint32
|
||||
gl.GenBuffers(1, &vbo)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
|
||||
|
||||
var vao uint32
|
||||
gl.GenVertexArrays(1, &vao)
|
||||
gl.BindVertexArray(vao)
|
||||
gl.EnableVertexAttribArray(0)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
|
||||
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
|
||||
|
||||
return vao
|
||||
}
|
||||
|
||||
func compileShader(source string, shaderType uint32) (uint32, error) {
|
||||
shader := gl.CreateShader(shaderType)
|
||||
|
||||
csources, free := gl.Strs(source)
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
free()
|
||||
gl.CompileShader(shader)
|
||||
|
||||
var status int32
|
||||
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
|
||||
if status == gl.FALSE {
|
||||
var logLength int32
|
||||
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
|
||||
|
||||
log := strings.Repeat("\x00", int(logLength+1))
|
||||
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
|
||||
|
||||
return 0, fmt.Errorf("failed to compile %v: %v", source, log)
|
||||
}
|
||||
|
||||
return shader, nil
|
||||
}
|
||||
```
|
||||
|
||||
请在 Twitter [@kylewbanks][33] 上告诉我这篇文章对你是否有帮助,或者点击下方的关注,以便及时获取最新文章!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
|
||||
作者:[kylewbanks ][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://twitter.com/kylewbanks
|
||||
[1]:https://kylewbanks.com/category/golang
|
||||
[2]:https://kylewbanks.com/category/opengl
|
||||
[3]:https://twitter.com/intent/tweet?text=OpenGL%20%26%20Go%20Tutorial%20Part%201%3A%20Hello%2C%20OpenGL%20https%3A%2F%2Fkylewbanks.com%2Fblog%2Ftutorial-opengl-with-golang-part-1-hello-opengl%20by%20%40kylewbanks
|
||||
[4]:mailto:?subject=Check%20Out%20%22OpenGL%20%26%20Go%20Tutorial%20Part%201%3A%20Hello%2C%20OpenGL%22&body=https%3A%2F%2Fkylewbanks.com%2Fblog%2Ftutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[5]:https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fkylewbanks.com%2Fblog%2Ftutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[6]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[7]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[8]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[9]:https://github.com/KyleBanks/conways-gol
|
||||
[10]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[11]:http://www.glfw.org/
|
||||
[12]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[13]:https://kylewbanks.com/blog/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[14]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl
|
||||
[15]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[16]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[17]:https://github.com/KyleBanks/conways-gol
|
||||
[18]:https://twitter.com/kylewbanks
|
||||
[19]:https://www.opengl.org/
|
||||
[20]:https://golang.org/
|
||||
[21]:https://github.com/go-gl/gl
|
||||
[22]:https://en.wikipedia.org/wiki/Conway's_Game_of_Life
|
||||
[23]:https://github.com/KyleBanks/conways-gol
|
||||
[24]:https://en.wikipedia.org/wiki/Conway's_Game_of_Life
|
||||
[25]:https://github.com/KyleBanks/conways-gol
|
||||
[26]:http://www.glfw.org/
|
||||
[27]:https://github.com/go-gl/glfw
|
||||
[28]:http://www.glfw.org/docs/latest/window_guide.html#buffer_swap
|
||||
[29]:https://www.quora.com/What-is-a-vertex-shader-and-what-is-a-fragment-shader/answer/Harold-Serrano?srid=aVb
|
||||
[30]:https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/glsl_overview.php
|
||||
[31]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board
|
||||
[32]:https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game
|
||||
[33]:https://twitter.com/kylewbanks
|
Loading…
Reference in New Issue
Block a user